Ampliar el marco de vidrio en una aplicación de WPF

En este tema se muestra cómo ampliar el marco de vidrio de Windows Vista en el área cliente de una aplicación de Windows Presentation Foundation (WPF).

Nota

Este ejemplo solo funciona en una máquina de Windows Vista que ejecute el Administrador de ventanas de escritorio (DWM) con efecto de cristal habilitado. La edición Home Basic de Windows Vista no admite el efecto de cristal transparente. Las áreas que normalmente se representarían con el efecto de cristal transparente en otras ediciones de Windows Vista se representan opacas.

Marco de vidrio ampliado en una barra de direcciones

En la siguiente imagen se muestra el marco de vidrio ampliado en la barra de direcciones de Internet Explorer 7:

Captura de pantalla que muestra el marco de vidrio extendido detrás de la barra de direcciones de IE7.

Para ampliar el marco de cristal en una aplicación WPF se requiere acceso a la API no administrada. En el siguiente ejemplo de código se realiza una PInvoke para las dos API necesarias para ampliar el marco en el área cliente. Cada una de estas API se declaran en una clase denominada NonClientRegionAPI.

[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
    public int cxLeftWidth;      // width of left border that retains its size
    public int cxRightWidth;     // width of right border that retains its size
    public int cyTopHeight;      // height of top border that retains its size
    public int cyBottomHeight;   // height of bottom border that retains its size
};

[DllImport("DwmApi.dll")]
public static extern int DwmExtendFrameIntoClientArea(
    IntPtr hwnd,
    ref MARGINS pMarInset);
<StructLayout(LayoutKind.Sequential)>
Public Structure MARGINS
    Public cxLeftWidth As Integer ' width of left border that retains its size
    Public cxRightWidth As Integer ' width of right border that retains its size
    Public cyTopHeight As Integer ' height of top border that retains its size
    Public cyBottomHeight As Integer ' height of bottom border that retains its size
End Structure

<DllImport("DwmApi.dll")>
Public Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef pMarInset As MARGINS) As Integer
End Function

DwmExtendFrameIntoClientArea es la función de DWM que amplia el marco en el área cliente. Toma dos parámetros; un identificador de ventana y una estructura MARGINS. MARGINS se usa para indicarle al DWM cuánto más debe ampliarse el marco en el área cliente.

Marco de vidrio ampliado en el evento Loaded

Para usar la función DwmExtendFrameIntoClientArea, debe obtenerse un identificador de ventana. En WPF, el manipulador de ventana se puede obtener de la propiedad Handle de HwndSource. En el ejemplo siguiente, el marco se amplía en el área cliente en el evento Loaded de la ventana.

void OnLoaded(object sender, RoutedEventArgs e)
{
   try
   {
      // Obtain the window handle for WPF application
      IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
      HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
      mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);

      // Get System Dpi
      System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(mainWindowPtr);
      float DesktopDpiX = desktop.DpiX;
      float DesktopDpiY = desktop.DpiY;

      // Set Margins
      NonClientRegionAPI.MARGINS margins = new NonClientRegionAPI.MARGINS();

      // Extend glass frame into client area
      // Note that the default desktop Dpi is 96dpi. The  margins are
      // adjusted for the system Dpi.
      margins.cxLeftWidth = Convert.ToInt32(5 * (DesktopDpiX / 96));
      margins.cxRightWidth = Convert.ToInt32(5 * (DesktopDpiX / 96));
      margins.cyTopHeight = Convert.ToInt32(((int)topBar.ActualHeight + 5) * (DesktopDpiX / 96));
      margins.cyBottomHeight = Convert.ToInt32(5 * (DesktopDpiX / 96));

      int hr = NonClientRegionAPI.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
      //
      if (hr < 0)
      {
         //DwmExtendFrameIntoClientArea Failed
      }
   }
   // If not Vista, paint background white.
   catch (DllNotFoundException)
   {
      Application.Current.MainWindow.Background = Brushes.White;
   }
}

Marco de vidrio ampliado en el área cliente

En el ejemplo siguiente se muestra una ventana simple en la que el marco se amplía en el área cliente. El marco se amplía por detrás del borde superior que contiene los dos objetos TextBox.

<Window x:Class="SDKSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Extended Glass in WPF" Height="300" Width="400"
    Loaded="OnLoaded" Background="Transparent"
    >
  <Grid ShowGridLines="True">
    <DockPanel Name="mainDock">
      <!-- The border is used to compute the rendered height with margins.
           topBar contents will be displayed on the extended glass frame.-->
      <Border Name="topBar" DockPanel.Dock="Top" >
        <Grid Name="grid">
          <Grid.ColumnDefinitions>
            <ColumnDefinition MinWidth="100" Width="*"/>
            <ColumnDefinition Width="Auto"/>
          </Grid.ColumnDefinitions>
          <TextBox Grid.Column="0" MinWidth="100" Margin="0,0,10,5">Path</TextBox>
          <TextBox Grid.Column="1" MinWidth="75" Margin="0,0,0,5">Search</TextBox>
        </Grid>
      </Border>
      <Grid DockPanel.Dock="Top" >
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" AcceptsReturn="True"/>
      </Grid>
    </DockPanel>
  </Grid>
</Window>

En la siguiente imagen se muestra el marco de vidrio ampliado en una aplicación WPF:

Captura de pantalla que muestra un marco de vidrio en la aplicación de WPF.

Vea también