WPF无边界窗口的DropShadow
我有一个WindowStyle设置为无的WPF窗口。 有什么办法可以强制这个窗口放下阴影(就像WindowStyle不是没有的时候那样)? 我不想将AllowTransparency设置为true,因为它会影响性能。 而且我也不想禁用硬件渲染(我在某处阅读透明性能更好,禁用它)。
我已经写了一个能够完成你想要的东西的小实用程序类:在无边框Window
放置标准阴影,但AllowsTransparency
设置为false
。
你只需要调用DropShadowToWindow(Window window)
方法。 最好是在窗口的构造函数的InitializeComponent()
之后进行这个调用,但是即使在窗口显示之后调用它,它也可以工作。
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); /// <summary> /// 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). /// </summary> /// <param name="window">Window to which the shadow will be applied</param> 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); } /// <summary> /// The actual method that makes API calls to drop the shadow to the window /// </summary> /// <param name="window">Window to which the shadow will be applied</param> /// <returns>True if the method succeeded, false if not</returns> 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; } } }
使用Microsoft WPF Shell Integration Library ,更简单,性能更好
帕特里克的答案很好,除了当一个win32窗口托pipe。 当发生这种情况时,您会注意到托pipe的窗口被“清除”(看起来窗户正在将“玻璃板”效果应用于整个托pipe窗口)。 当在本地定义结构时,这种奇怪的行为是固定的,例如
[StructLayout(LayoutKind.Sequential)] public struct Margins { public int Left; public int Right; public int Top; public int Bottom; }
如果允许窗口调整边框大小,可以通过将ResizeMode
设置为ResizeMode
来获得OS阴影。 然后,您可以将MaxWidth
, MinWidth
, MaxHeight
和MinHeight
为将阻止resize的值。
如果你有一个没有风格的无边框窗口,你将不得不为自己的可视化树中的窗口提供所有的外观,包括一个阴影,因为这个设置的组合与说你不想要什么OS提供。
编辑:
从这一点来看,如果你的窗口大小是固定的,只需要添加dropshadow,也许作为一个<Rectangle/>
作为<Canvas/>
的内容中的第一个元素
像这样的东西:
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" AllowsTransparency="True" Background="Transparent" WindowStyle="None"> <Canvas> <Rectangle Fill="#33000000" Width="100" Height="100"/> <Rectangle Fill="#FFFF0000" Width="95" Height="95" /> </Canvas> </Window>
请注意,第一个Rectangle
的Fill
属性是部分透明的,您也可以使用Rectangle
的Opacity
属性。 您可以使用自己或不同形状的graphics来自定义投影的外观。
请注意,这违反了要求AllowsTransparency
为False
要求,但您别无select:如果您需要透明度,则必须允许。
为什么不创build与你的“窗口”相同的对象,但更大和后面的阴影。
<Window x:Class="WPF_Custom_Look.ShadowWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ShadowWindow" Height="400" Width="450" ResizeMode="NoResize" Background="Transparent" AllowsTransparency="True" WindowStyle="None"> <Grid> <Rectangle Fill="Black" Width="330" Opacity="0.5" Height="279"> <Rectangle.Effect> <BlurEffect Radius="30"/> </Rectangle.Effect> </Rectangle> <Rectangle Fill="#FFFDFDFD" Width="312" Height="260"/> </Grid>
或者如果你需要一个透明的标题栏,它可以被<Border>
replace
<Canvas> <Border BorderBrush="Black" BorderThickness="7" Height="195" Width="304" Canvas.Left="53" Canvas.Top="25"> <Border.Effect> <BlurEffect Radius="20"/> </Border.Effect> </Border> <Rectangle Fill="#FF86B0F9" Width="285" Height="177" Opacity="0.7" Canvas.Left="62" Canvas.Top="34" MouseDown="Border_MouseDown"/> <Rectangle Fill="#FFFDFDFD" Width="285" Height="143" Canvas.Left="62" Canvas.Top="68"/> </Canvas>
编辑:我只是注意到OP希望AllowsTransparency设置为False。 如果没有“真实”,我就看不到阴影。