WPF无边框窗口的DropShadow

WPF无边框窗口的DropShadow,wpf,windows,transparency,dropshadow,Wpf,Windows,Transparency,Dropshadow,我有一个WPF窗口,窗口样式设置为“无”。有没有什么方法可以强制此窗口投射阴影(就像WindowsStyle不为none时得到的阴影)?我不想将AllowTransparency设置为true,因为它会影响性能。而且我也不想禁用硬件渲染(我在某个地方读到,禁用它后透明度会更好)。如果您允许窗口具有调整大小的边框,通过将ResizeMode设置为CanResize,那么您将得到操作系统的阴影。然后,您可以将MaxWidth、MinWidth、MaxHeight和MinHeight设置为阻止调整大小

我有一个WPF窗口,窗口样式设置为“无”。有没有什么方法可以强制此窗口投射阴影(就像WindowsStyle不为none时得到的阴影)?我不想将AllowTransparency设置为true,因为它会影响性能。而且我也不想禁用硬件渲染(我在某个地方读到,禁用它后透明度会更好)。

如果您允许窗口具有调整大小的边框,通过将
ResizeMode
设置为
CanResize
,那么您将得到操作系统的阴影。然后,您可以将
MaxWidth
MinWidth
MaxHeight
MinHeight
设置为阻止调整大小的值

如果您有一个没有样式的无边框窗口,那么您必须在自己的视觉树中提供该窗口的所有外观,包括阴影,因为这种设置组合与表示您不想要操作系统提供的相同

编辑:

从那时起,如果窗口大小是固定的,只需添加dropshadow,可能作为
作为
内容中的第一个元素

大概是这样的:

<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>

请注意,第一个
矩形的
Fill
属性部分透明,您也可以使用
矩形的
Opacity
属性。您可以使用自己的图形或其他形状来自定义阴影的外观


请注意,这违反了您的要求,即要求
allowsttransparency
be
False
,但您别无选择:如果您想要透明,您必须允许透明

我编写了一个小实用程序类,它能够完全实现您想要的功能:在无边界的
窗口上放置一个标准阴影,但将
allowTransparency
设置为
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;
        }
    }
}
使用系统;
使用系统、绘图、打印;
使用System.Runtime.InteropServices;
使用System.Windows;
使用System.Windows.Interop;
公共静态类DwmDropShadow
{
[DllImport(“dwmapi.dll”,PreserveSig=true)]
私有静态外部int DwmSetWindowAttribute(IntPtr hwnd、int attr、ref int attrValue、int attrSize);
[DllImport(“dwmapi.dll”)]
私有静态外部int DwmExtendFrameIntoClientArea(IntPtr hWnd,ref Margins pMarInset);
/// 
///将标准阴影放置到WPF窗口,即使该窗口是无边界的。仅适用于DWM(Windows Vista或更高版本)。
///此方法比将AllowTransparency设置为true并使用DropShadow效果更有效,
///因为AllowTransparency涉及到一个巨大的性能问题(所有窗口的硬件加速都被关闭)。
/// 
///将应用阴影的窗口
公共静态无效DropShadowToWindow(窗口)
{
如果(!DropShadow(窗口))
{
window.SourceInitialized+=新事件处理程序(window\u SourceInitialized);
}
}
私有静态无效窗口\u SourceInitialized(对象发送方,事件参数e)
{
窗口=(窗口)发送方;
投影(窗口);
window.SourceInitialized-=新事件处理程序(window\u SourceInitialized);
}
/// 
///使API调用将阴影放置到窗口的实际方法
/// 
///将应用阴影的窗口
///如果方法成功,则为True,否则为false
私有静态bool DropShadow(窗口)
{
尝试
{
WindowInteropHelper helper=新的WindowInteropHelper(窗口);
int-val=2;
int ret1=DwmSetWindowAttribute(helper.Handle,2,ref val,4);
如果(ret1==0)
{
边距m=新边距{底部=0,左侧=0,右侧=0,顶部=0};
int ret2=dwmextendframeintoclienterea(helper.Handle,ref m);
返回ret2==0;
}
其他的
{
返回false;
}
}
捕获(例外情况除外)
{
//可能未找到dwmapi.dll(不兼容的操作系统)
返回false;
}
}
}

Patrick的答案非常有效,除非是在win32窗口上。 当这种情况发生时,您会注意到主体窗口已“清洗”(看起来windows正在对整个主体窗口应用“玻璃板”效果)。 这种奇怪的行为在局部定义结构时是固定的, e、 g


为什么不只是用与“窗口”相同的对象创建阴影,而是在其后面创建更大的阴影呢

<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>

或者,如果您需要一个透明的标题栏,可以用



编辑:我刚刚注意到OP希望AllowTransparency设置为False。thouth,如果阴影不为“真”,我就看不到它可以工作。

关于编辑:我确实尝试过类似的方法,但它确实会降低性能。我是在Windows XP上这样做的,对Vista/7一无所知。您不必在将
allowsttransparency
设置为
False
和能够放置阴影之间进行选择。您可以在位于主窗口边缘的4个窗口中将
allowTransparecency
设置为
True
,这4个窗口将负责放置阴影。这样,主窗口的性能将保持不变。这很好,但我遇到了一个问题,打开子窗口(也使用dropshadow)会减少父窗口上的dropshadow,然后当关闭子窗口时,会将其完全删除。奇怪的虫子,没找到是什么引起的
<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>
<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>