?WPF 窗體設置亞克力效果
控件名:WindowAcrylicBlur
作者: WPFDevelopersOrg ?- 吳鋒
原文鏈接: ? ?https://github.com/WPFDevelopersOrg/WPFDevelopers
框架使用大于等于
.NET40
。Visual Studio 2022
。項目使用 MIT 開源許可協議。
WindowAcrylicBlur
設置亞克力顏色。Opacity
設置透明度。

1) 準備WindowAcrylicBlur.cs如下:
using?System;
using?System.Runtime.InteropServices;
using?System.Windows;
using?System.Windows.Interop;
using?System.Windows.Media;
using?Microsoft.Win32;
using?Microsoft.Windows.Shell;namespace?WPFDevelopers.Controls
{internal?enum?AccentState{ACCENT_DISABLED?=?0,ACCENT_ENABLE_GRADIENT?=?1,ACCENT_ENABLE_TRANSPARENTGRADIENT?=?2,ACCENT_ENABLE_BLURBEHIND?=?3,ACCENT_ENABLE_ACRYLICBLURBEHIND?=?4,ACCENT_INVALID_STATE?=?5}[StructLayout(LayoutKind.Sequential)]internal?struct?AccentPolicy{public?AccentState?AccentState;public?uint?AccentFlags;public?uint?GradientColor;public?uint?AnimationId;}[StructLayout(LayoutKind.Sequential)]internal?struct?WindowCompositionAttributeData{public?WindowCompositionAttribute?Attribute;public?IntPtr?Data;public?int?SizeOfData;}internal?enum?WindowCompositionAttribute{//?...WCA_ACCENT_POLICY?=?19//?...}internal?class?WindowOldConfig{public?bool?AllowsTransparency;public?Brush?Background;public?WindowChrome?WindowChrome;public?WindowStyle?WindowStyle?=?WindowStyle.SingleBorderWindow;}internal?class?WindowOSHelper{public?static?Version?GetWindowOSVersion(){var?regKey?=?Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows?NT\CurrentVersion");int?major;int?minor;int?build;int?revision;try{var?str?=?regKey.GetValue("CurrentMajorVersionNumber")?.ToString();int.TryParse(str,?out?major);str?=?regKey.GetValue("CurrentMinorVersionNumber")?.ToString();int.TryParse(str,?out?minor);str?=?regKey.GetValue("CurrentBuildNumber")?.ToString();int.TryParse(str,?out?build);str?=?regKey.GetValue("BaseBuildRevisionNumber")?.ToString();int.TryParse(str,?out?revision);return?new?Version(major,?minor,?build,?revision);}catch?(Exception){return?new?Version(0,?0,?0,?0);}finally{regKey.Close();}}}public?class?WindowAcrylicBlur?:?Freezable{private?static?readonly?Color?_BackgtoundColor?=?Color.FromArgb(0x01,?0,?0,?0);?//設置透明色?防止穿透[DllImport("user32.dll")]internal?static?extern?int?SetWindowCompositionAttribute(IntPtr?hwnd,?ref?WindowCompositionAttributeData?data);private?static?bool?EnableAcrylicBlur(Window?window,?Color?color,?double?opacity,?bool?enable){if?(window?==?null)return?false;AccentState?accentState;var?vOsVersion?=?WindowOSHelper.GetWindowOSVersion();if?(vOsVersion?>?new?Version(10,?0,?17763))?//1809accentState?=?enable???AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND?:?AccentState.ACCENT_DISABLED;else?if?(vOsVersion?>?new?Version(10,?0))accentState?=?enable???AccentState.ACCENT_ENABLE_BLURBEHIND?:?AccentState.ACCENT_DISABLED;elseaccentState?=?AccentState.ACCENT_DISABLED;if?(opacity?>?1)opacity?=?1;var?windowHelper?=?new?WindowInteropHelper(window);var?accent?=?new?AccentPolicy();var?opacityIn?=?(uint)?(255?*?opacity);accent.AccentState?=?accentState;if?(enable){var?blurColor?=?(uint)?((color.R?<<?0)?|?(color.G?<<?8)?|?(color.B?<<?16)?|?(color.A?<<?24));var?blurColorIn?=?blurColor;if?(opacityIn?>?0)blurColorIn?=?(opacityIn?<<?24)?|?(blurColor?&?0xFFFFFF);else?if?(opacityIn?==?0?&&?color.A?==?0)blurColorIn?=?(0x01?<<?24)?|?(blurColor?&?0xFFFFFF);if?(accent.GradientColor?==?blurColorIn)return?true;accent.GradientColor?=?blurColorIn;}var?accentStructSize?=?Marshal.SizeOf(accent);var?accentPtr?=?Marshal.AllocHGlobal(accentStructSize);Marshal.StructureToPtr(accent,?accentPtr,?false);var?data?=?new?WindowCompositionAttributeData();data.Attribute?=?WindowCompositionAttribute.WCA_ACCENT_POLICY;data.SizeOfData?=?accentStructSize;data.Data?=?accentPtr;SetWindowCompositionAttribute(windowHelper.Handle,?ref?data);Marshal.FreeHGlobal(accentPtr);return?true;}private?static?void?Window_Initialized(object?sender,?EventArgs?e){if?(!(sender?is?Window?window))return;var?config?=?new?WindowOldConfig{WindowStyle?=?window.WindowStyle,AllowsTransparency?=?window.AllowsTransparency,Background?=?window.Background};var?vWindowChrome?=?WindowChrome.GetWindowChrome(window);if?(vWindowChrome?==?null){window.WindowStyle?=?WindowStyle.None;?//一定要將窗口的背景色改為透明才行window.AllowsTransparency?=?true;?//一定要將窗口的背景色改為透明才行window.Background?=?new?SolidColorBrush(_BackgtoundColor);?//一定要將窗口的背景色改為透明才行}else{config.WindowChrome?=?new?WindowChrome{GlassFrameThickness?=?vWindowChrome.GlassFrameThickness};window.Background?=?Brushes.Transparent;?//一定要將窗口的背景色改為透明才行var?vGlassFrameThickness?=?vWindowChrome.GlassFrameThickness;vWindowChrome.GlassFrameThickness?=?new?Thickness(0,?vGlassFrameThickness.Top,?0,?0);}SetWindowOldConfig(window,?config);window.Initialized?-=?Window_Initialized;}private?static?void?Window_Loaded(object?sender,?RoutedEventArgs?e){if?(!(sender?is?Window?window))return;var?vBlur?=?GetWindowAcrylicBlur(window);if?(vBlur?!=?null)EnableAcrylicBlur(window,?vBlur.BlurColor,?vBlur.Opacity,?true);window.Loaded?-=?Window_Loaded;}protected?override?Freezable?CreateInstanceCore(){throw?new?NotImplementedException();}protected?override?void?OnChanged(){base.OnChanged();}protected?override?void?OnPropertyChanged(DependencyPropertyChangedEventArgs?e){base.OnPropertyChanged(e);}#region?開啟Win11風格public?static?WindowAcrylicBlur?GetWindowAcrylicBlur(DependencyObject?obj){return?(WindowAcrylicBlur)?obj.GetValue(WindowAcrylicBlurProperty);}public?static?void?SetWindowAcrylicBlur(DependencyObject?obj,?WindowAcrylicBlur?value){obj.SetValue(WindowAcrylicBlurProperty,?value);}public?static?readonly?DependencyProperty?WindowAcrylicBlurProperty?=DependencyProperty.RegisterAttached("WindowAcrylicBlur",?typeof(WindowAcrylicBlur),typeof(WindowAcrylicBlur),new?PropertyMetadata(default(WindowAcrylicBlur),?OnWindowAcryBlurPropertyChangedCallBack));private?static?void?OnWindowAcryBlurPropertyChangedCallBack(DependencyObject?d,DependencyPropertyChangedEventArgs?e){if?(!(d?is?Window?window))return;if?(e.OldValue?==?null?&&?e.NewValue?==?null)return;if?(e.OldValue?==?null?&&?e.NewValue?!=?null){window.Initialized?+=?Window_Initialized;window.Loaded?+=?Window_Loaded;}if?(e.OldValue?!=?null?&&?e.NewValue?==?null){var?vConfig?=?GetWindowOldConfig(d);if?(vConfig?!=?null){window.WindowStyle?=?vConfig.WindowStyle;window.AllowsTransparency?=?vConfig.AllowsTransparency;window.Background?=?vConfig.Background;if?(vConfig.WindowChrome?!=?null){var?vWindowChrome?=?WindowChrome.GetWindowChrome(window);if?(vWindowChrome?!=?null)vWindowChrome.GlassFrameThickness?=?vConfig.WindowChrome.GlassFrameThickness;}}}if?(e.OldValue?==?e.NewValue){if?(!window.IsLoaded)return;var?vBlur?=?e.NewValue?as?WindowAcrylicBlur;if?(vBlur?==?null)return;EnableAcrylicBlur(window,?vBlur.BlurColor,?vBlur.Opacity,?true);}}#endregion#region?內部設置private?static?WindowOldConfig?GetWindowOldConfig(DependencyObject?obj){return?(WindowOldConfig)?obj.GetValue(WindowOldConfigProperty);}private?static?void?SetWindowOldConfig(DependencyObject?obj,?WindowOldConfig?value){obj.SetValue(WindowOldConfigProperty,?value);}//?Using?a?DependencyProperty?as?the?backing?store?for?WindowOldConfig.??This?enables?animation,?styling,?binding,?etc...private?static?readonly?DependencyProperty?WindowOldConfigProperty?=DependencyProperty.RegisterAttached("WindowOldConfig",?typeof(WindowOldConfig),?typeof(WindowAcrylicBlur),new?PropertyMetadata(default(WindowOldConfig)));#endregion#regionpublic?Color?BlurColor{get?=>?(Color)?GetValue(BlurColorProperty);set?=>?SetValue(BlurColorProperty,?value);}//?Using?a?DependencyProperty?as?the?backing?store?for?BlurColor.??This?enables?animation,?styling,?binding,?etc...public?static?readonly?DependencyProperty?BlurColorProperty?=DependencyProperty.Register("BlurColor",?typeof(Color),?typeof(WindowAcrylicBlur),new?PropertyMetadata(default(Color)));public?double?Opacity{get?=>?(double)?GetValue(OpacityProperty);set?=>?SetValue(OpacityProperty,?value);}//?Using?a?DependencyProperty?as?the?backing?store?for?Opacity.??This?enables?animation,?styling,?binding,?etc...public?static?readonly?DependencyProperty?OpacityProperty?=DependencyProperty.Register("Opacity",?typeof(double),?typeof(WindowAcrylicBlur),new?PropertyMetadata(default(double)));#endregion}
}
2) 使用AcrylicBlurWindowExample.xaml如下:
<Window?x:Class="WPFDevelopers.Samples.ExampleViews.AcrylicBlurWindowExample"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"mc:Ignorable="d"?WindowStartupLocation="CenterScreen"ResizeMode="CanMinimize"Title="Login"?Height="350"?Width="400"><wpfdev:WindowChrome.WindowChrome><wpfdev:WindowChrome??GlassFrameThickness="0?1?0?0"/></wpfdev:WindowChrome.WindowChrome><wpfdev:WindowAcrylicBlur.WindowAcrylicBlur><wpfdev:WindowAcrylicBlur?BlurColor="AliceBlue"?Opacity="0.2"/></wpfdev:WindowAcrylicBlur.WindowAcrylicBlur><Grid><Grid.RowDefinitions><RowDefinition?Height="40"/><RowDefinition/></Grid.RowDefinitions><StackPanel?HorizontalAlignment="Right"?Orientation="Horizontal"Grid.Column="1"wpfdev:WindowChrome.IsHitTestVisibleInChrome="True"><Button?Style="{DynamicResource?WindowButtonStyle}"Command="{Binding?CloseCommand,RelativeSource={RelativeSource?AncestorType=local:AcrylicBlurWindowExample}}"?Cursor="Hand"><Path?Width="10"?Height="10"HorizontalAlignment="Center"VerticalAlignment="Center"Data="{DynamicResource?PathMetroWindowClose}"Fill="Red"Stretch="Fill"?/></Button></StackPanel><StackPanel?Grid.Row="1"?Margin="40,0,40,0"wpfdev:WindowChrome.IsHitTestVisibleInChrome="True"><Image?Source="/WPFDevelopers.ico"?Width="80"?Height="80"/><TextBox?wpfdev:ElementHelper.IsWatermark="True"?wpfdev:ElementHelper.Watermark="賬戶"?Margin="0,20,0,0"?Cursor="Hand"/><PasswordBox?wpfdev:ElementHelper.IsWatermark="True"?wpfdev:ElementHelper.Watermark="密碼"??Margin="0,20,0,0"?Cursor="Hand"/><Button?x:Name="LoginButton"?Content="登?錄"?Margin="0,20,0,0"Style="{StaticResource?PrimaryButton}"/><Grid?Margin="0?20?0?0"><TextBlock?FontSize="12"><Hyperlink?Foreground="Black"?TextDecorations="None">忘記密碼</Hyperlink></TextBlock><TextBlock?FontSize="12"?HorizontalAlignment="Right"?Margin="0?0?-1?0"><Hyperlink?Foreground="#4370F5"?TextDecorations="None">注冊賬號</Hyperlink></TextBlock></Grid></StackPanel></Grid>
</Window>
3) 使用AcrylicBlurWindowExample.xaml.cs如下:
using?System.Windows;
using?System.Windows.Input;
using?WPFDevelopers.Samples.Helpers;namespace?WPFDevelopers.Samples.ExampleViews
{///?<summary>///?AcrylicBlurWindowExample.xaml?的交互邏輯///?</summary>public?partial?class?AcrylicBlurWindowExample?:?Window{public?AcrylicBlurWindowExample(){InitializeComponent();}public?ICommand?CloseCommand?=>?new?RelayCommand(obj?=>{Close();});}
}
?鳴謝 - 吳鋒

Github|AcrylicBlurWindowExample[1]
碼云|AcrylicBlurWindowExample[2]
使用 SetWindowCompositionAttribute 來控制程序的窗口邊框和背景可以做 Acrylic 亞克力效果、模糊效果、主題色效果等[3]
參考資料
[1]
Github|AcrylicBlurWindowExample: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/AcrylicBlurWindowExample.xaml
[2]碼云|AcrylicBlurWindowExample: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/AcrylicBlurWindowExample.xaml
[3]使用 SetWindowCompositionAttribute 來控制程序的窗口邊框和背景可以做 Acrylic 亞克力效果、模糊效果、主題色效果等: https://blog.walterlv.com/post/set-window-composition-attribute.html