DropShadow para janela sem bordas do WPF

Eu tenho uma janela do WPF com WindowStyle definido como nenhum. Existe alguma maneira que eu possa forçar esta janela para soltar uma sombra (como o que você começa quando WindowStyle não é nenhum)? Eu não quero definir AllowTransparency como true, porque afeta o desempenho. E eu também não quero desativar a renderização de hardware (eu li em algum lugar que a transparência funciona melhor com ele desativado).

Eu escrevi uma pequena class de utilitário que é capaz de fazer exatamente o que você quer: soltar uma sombra padrão sobre uma Window sem AllowsTransparency mas com AllowsTransparency definido como false .

Você só precisa chamar o método DropShadowToWindow(Window window) . É preferível que você faça essa chamada logo após o InitializeComponent() do construtor da janela, mas ela funcionará mesmo se você a chamar depois que a janela for mostrada.

 using System; using System.Drawing.Printing; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; public static class DwmDropShadow { [DllImport("dwmapi.dll", PreserveSig = true)] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); [DllImport("dwmapi.dll")] private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset); ///  /// Drops a standard shadow to a WPF Window, even if the window is borderless. Only works with DWM (Windows Vista or newer). /// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect, /// as AllowsTransparency involves a huge performance issue (hardware acceleration is turned off for all the window). ///  /// Window to which the shadow will be applied public static void DropShadowToWindow(Window window) { if (!DropShadow(window)) { window.SourceInitialized += new EventHandler(window_SourceInitialized); } } private static void window_SourceInitialized(object sender, EventArgs e) { Window window = (Window)sender; DropShadow(window); window.SourceInitialized -= new EventHandler(window_SourceInitialized); } ///  /// The actual method that makes API calls to drop the shadow to the window ///  /// Window to which the shadow will be applied /// True if the method succeeded, false if not private static bool DropShadow(Window window) { try { WindowInteropHelper helper = new WindowInteropHelper(window); int val = 2; int ret1 = DwmSetWindowAttribute(helper.Handle, 2, ref val, 4); if (ret1 == 0) { Margins m = new Margins { Bottom = 0, Left = 0, Right = 0, Top = 0 }; int ret2 = DwmExtendFrameIntoClientArea(helper.Handle, ref m); return ret2 == 0; } else { return false; } } catch (Exception ex) { // Probably dwmapi.dll not found (incompatible OS) return false; } } } 

Use a biblioteca de integração do Microsoft WPF Shell , mais fácil e com melhor desempenho

A resposta de Patrick funciona muito bem, exceto quando uma janela do win32 é hospedada. Quando isso acontece, você percebe que a janela hospedada está “desbotada” (parece que o Windows está aplicando o efeito “folha de vidro” a toda a janela hospedada). Esse comportamento estranho é corrigido ao definir a estrutura localmente, por exemplo

 [StructLayout(LayoutKind.Sequential)] public struct Margins { public int Left; public int Right; public int Top; public int Bottom; } 

Se você permitir que a janela tenha bordas de redimensionamento, definindo ResizeMode como CanResize , obterá o sombreamento do sistema operacional. Em seguida, você pode definir o MaxWidth , MinWidth , MaxHeight e MinHeight para valores que impedirão o redimensionamento.

Se você tem uma janela sem borda sem um estilo, você terá que fornecer toda a aparência para a janela em sua própria tree visual, incluindo uma sombra projetada, já que essa combinação de configurações é a mesma que dizer que você não quer o SO fornece.

EDITAR:

A partir desse ponto, se o tamanho da sua janela é fixo, simplesmente adicione a sombra, talvez como um como o primeiro elemento no conteúdo de um

algo assim:

       

Observe que a propriedade Fill desse primeiro Rectangle é parcialmente transparente, o que você também pode fazer com a propriedade Opacity do Rectangle . Você pode usar um gráfico próprio ou uma forma diferente para personalizar a aparência do sombreamento.

Observe que isso viola sua exigência de que AllowsTransparency seja False , mas você não tem escolha: se quiser transparência, é necessário permitir isso.

Por que não criar a sombra com o mesmo object que a sua “janela”, mas maior e por trás dela?

          

Ou se você precisar de uma barra de título transparente, ela pode ser substituída por um

          

Edit: Eu só notei OP quer AllowsTransparency definido como False. Eu não posso ver uma sombra para trabalhar sem que seja “Verdadeiro”, na verdade.