Extender marco de vidrio en una aplicación WPF

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

Nota:

Este ejemplo solo funcionará en una máquina Windows Vista que ejecute desktop Window Manager (DWM) con vidrio habilitado. La edición Windows Vista Home Basic no admite el efecto de vidrio transparente. Las áreas que normalmente se representarían con el efecto de vidrio transparente en otras ediciones de Windows Vista se representan opacos.

Marco de vidrio extendido en una barra de direcciones

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

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

Para ampliar el marco de vidrio en una aplicación WPF, se necesita acceso a la API no administrada. En el ejemplo de código siguiente se realiza una invocación de plataforma (pinvoke) para las dos API necesarias para extender el marco al área de cliente. Cada una de estas API se declara 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 DWM que extiende el marco al área cliente. Toma dos parámetros; un identificador de ventana y una estructura MARGINS. MARGINS se usa para indicar al DWM cuánto más debe extenderse el marco extra en el área de cliente.

Marco de vidrio extendido en el evento Loaded

Para usar la función DwmExtendFrameIntoClientArea , se debe obtener un identificador de ventana. En WPF, el identificador de ventana se puede obtener de la Handle propiedad de un HwndSource. En el ejemplo siguiente, el marco se extiende al área del cliente durante 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 del cliente

En el ejemplo siguiente se muestra una ventana sencilla en la que el marco se extiende al área cliente. El marco se extiende detrás del borde superior que contiene los dos TextBox objetos.

<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 imagen siguiente se muestra el marco de vidrio extendido en una aplicación WPF:

Captura de pantalla que muestra un marco de cristal extendido en una aplicación WPF.

Consulte también