[英]DropShadow for WPF Borderless Window
我有一个WPF窗口,WindowStyle设置为none。 有什么方法可以强制这个窗口放一个阴影(就像你在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;
}
}
}
帕特里克的答案很有效,除非托管win32窗口。 当发生这种情况时,您会注意到托管窗口“被淘汰”(看起来窗口正在将“玻璃板”效果应用于整个托管窗口)。 在本地定义结构时,这种奇怪的行为是固定的,例如
[StructLayout(LayoutKind.Sequential)]
public struct Margins
{
public int Left;
public int Right;
public int Top;
public int Bottom;
}
如果您允许窗口调整边框大小,通过将ResizeMode
设置为CanResize
,您将获得操作系统投影。 然后,您可以将MaxWidth
, MinWidth
, MaxHeight
和MinHeight
为阻止调整大小的值。
如果你有一个没有样式的无边框窗口,你必须在你自己的可视化树中提供窗口的所有外观,包括一个投影,因为这种设置组合与你不想要什么操作系统相同提供。
编辑:
从那时起,如果您的窗口大小是固定的,只需添加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
属性。 您可以使用自己的图形或不同的形状来自定义投影的外观。
请注意,这违反了您允许AllowsTransparency
为False
要求,但您别无选择:如果您想要透明度,则必须允许它。
为什么不用与“窗口”相同的对象创建阴影,而在背后更大。
<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>
替换它
<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希望将AllowTransparency设置为False。 我不能看到阴影在没有“真实”的情况下工作,那么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.