我有一個WindowStyle設置爲無的WPF窗口。有什麼辦法可以強制這個窗口放下一個陰影(就像WindowStyle不是沒有的時候那樣)?我不想將AllowTransparency設置爲true,因爲它會影響性能。而且我也不想禁用硬件渲染(我在某處讀取透明度會更好地禁用它)。WPF無邊界窗口的DropShadow
回答
我寫了一個小工具類,它是能夠做到你想要什麼:刪除一個標準陰影無邊界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;
}
}
}
如果您允許窗口調整邊框大小,通過將ResizeMode
設置爲CanResize
,您將獲得OS陰影。然後,您可以將MaxWidth
,MinWidth
,MaxHeight
和MinHeight
設置爲阻止調整大小的值。
如果你有一個沒有風格的無邊界窗口,你將不得不爲你自己的可視化樹中的窗口提供所有的外觀,包括陰影,因爲這些設置組合與說你沒有想要什麼操作系統提供。
編輯:
從這一點來說,如果你的窗口大小是固定的,只需添加陰影效果,也許作爲一個<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
屬性是部分透明的,您也可以做012的Opacity
財產。您可以使用自己或不同形狀的圖形來自定義投影的外觀。
請注意,這違反了您的要求AllowsTransparency
爲False
,但您別無選擇:如果您想要透明度,則必須允許。
使用Microsoft WPF Shell Integration Library,更容易和更好的性能
3年後,鏈接已經死亡。 – 2014-11-28 22:22:35
@NickeManarin:一個簡單的搜索表明庫不再需要,因爲它在.NET 4.5中的System.Windows和System.Windows.Shell中實現https://mui.codeplex.com/workitem/19695 – 2014-12-05 13:29:19
NuGet:Install -Package Microsoft.Windows.Shell – Carol 2015-06-23 19:54:18
帕特里克的答案很好,除了當一個win32窗口託管。 發生這種情況時,您會注意到託管窗口「被清除」(看起來窗戶正在將「玻璃板」效果應用於整個託管窗口)。 這個奇怪的行爲在本地定義結構時是固定的,例如 例如
[StructLayout(LayoutKind.Sequential)]
public struct Margins
{
public int Left;
public int Right;
public int Top;
public int Bottom;
}
這是一個很好的觀點。同樣值得注意的是,這個問題只能在一小部分機器上重現,所以特別討厭。 – 2017-06-26 17:53:41
到目前爲止,我已經注意到它在英特爾高清520顯卡以及其他筆記本電腦上的其他英特爾高清顯卡上。 – 2017-06-26 19:01:37
另外,如果您將'Margins'轉換爲'class',那麼問題就會回來。它必須與'System.Drawing.Printing'也是'class'有關。 – 2017-06-26 19:40:34
爲什麼不只是創建與您的「窗口」相同的對象,但更大和後面的影子。
<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想AllowsTransparency設置爲False。如果沒有「真實」,我就看不到影子的工作。
- 1. 可移動的WPF無邊界窗口
- 2. 在wpf中移動無邊界窗口
- 3. 無邊界wpf窗口行爲.net 3.5
- 4. WPF無邊界窗口調整大小
- 5. WPF窗口邊界問題
- 6. 無邊界窗口monogame
- 7. CEF 3無邊界窗口
- 8. Eclipse 4 - 無邊界窗口
- 9. 調整邊界不窗口在WPF
- 10. WPF窗口拖動/移動邊界
- 11. Silverlight窗口邊界
- 12. Linux上的無邊界窗口
- 13. WPF列表框是無界的窗口
- 14. WPF無邊界窗口只是最大化主屏幕大小
- 15. WPF無邊框窗口的問題:
- 16. WPF中的無邊框窗口
- 17. pygame中的窗口邊界
- 18. 更改窗口的邊界
- 19. 無邊界窗口全功能
- 20. 無邊界窗口帶陰影和blurbehind
- 21. 如何使QML窗口無邊界?
- 22. 無邊界窗體邊緣
- 23. WPF無邊框窗口內利潤
- 24. WPF無邊框窗口按鈕
- 25. ncurses.h確定窗口邊界
- 26. 刪除最大化WPF自定義窗口的DropShadow
- 27. 在WPF中延伸到窗口邊界之外的網格上移動窗口
- 28. 航空邊界從我的WPF窗口隔斷空間
- 29. WPF檢測鼠標單擊窗口的邊界
- 30. wpf窗口邊界之外的光標移動事件
這很好,除了我在打開子窗口(也有陰影)時遇到問題時,它會減少父窗口的陰影,然後在關閉子窗口時將其完全刪除。奇怪的錯誤,沒有發現什麼造成它呢。它也似乎這樣做時,子窗口不使用陰影) – 2011-10-18 07:23:37
工作就像一個魅力。 :) 謝謝。 – 2013-05-29 13:49:00
注意:當我嘗試在本機應用程序中使用此方法時,直到我將邊距設置爲非零值時纔會出現陰影。 (對於無邊界窗口,只要與0不同,實際值似乎並不重要)。 – 2013-09-06 11:36:41