WPF实现窗体亚克力效果的示例代码
作者:驚鏵 发布时间:2022-07-25 10:38:08
标签:WPF,窗体,亚克力
WPF 窗体设置亚克力效果
框架使用大于等于.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)) //1809
accentState = enable ? AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND : AccentState.ACCENT_DISABLED;
else if (vOsVersion > new Version(10, 0))
accentState = enable ? AccentState.ACCENT_ENABLE_BLURBEHIND : AccentState.ACCENT_DISABLED;
else
accentState = 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
#region
public 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();
});
}
}
实现效果
来源:https://mp.weixin.qq.com/s/xFoqJqds249l0LotgDtsLg


猜你喜欢
- 1. 配置 * 具体步骤:编写一自定义 * 类实现接口 HandlerInterceptorHandlerInterceptor 接口: 可
- Spring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象,类似于Spring F
- Mybatis注解开发单表操作MyBatis的常用注解Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。我
- 最近做通讯录小屏机 联系人姓名显示--长度超过边界字体变小/** * 自定义TextView,文本内容自动调整字体大小以适应TextVie
- Intellij Idea打包Java项目打开模块设置如下图所示,选中需要打包的模块,右键点击,即会出现如下图所示的内容,点击Open Mo
- 看了下网上代码:我想要的效果如下图下划线和文字有15dp的间距 eeeeee的颜色上代码,<"1.0
- 目录创建线程管理线程销毁线程创建线程线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开
- Java事件处理机制和适配器最重要的是理解事件源,监视器,处理事件的接口的概念。1.事件源:是能够产生时间的对象都可以叫事件源,比如文本框,
- 基本思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后
- 现在,汽车的踪影无处不在,公路上疾驰,大街边临停,小区中停靠,车库里停泊。管理监控如此庞大数量的汽车是个头疼的问题。精明的人们把目光放在车牌
- 在进行C#应用程序开发的过程中,经常需要多窗体之间进行数据通信,本文举几个例子,把几种常用的通信方式总结一下,窗体界面如下图所示: 
- 有个小伙伴遇到了这样一个问题,就是AutoCompleteTextView实现自动填充的功能。同时要具备手机格式化的功能。下拉列表最后一行是
- java 多线程的三种构建方法继承Thread类创建线程类public class Thread extends Object
- 我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnIte
- 刚开始做开发学习的小伙伴可能在有一个知识上面有错误的认知,我们天天写程序是在Idea下写的,运行也是在Idea下运行的。但是实际开发完成后,
- 本文实例讲述了Android实现WebView删除缓存的方法。分享给大家供大家参考。具体如下:删除保存于手机上的缓存:// clear th
- 一、Rxjava使用场景为了模拟实际场景,从wanandroid网站找了二个接口,如下:(对Wanandroid表示感谢!)public i
- 一.有段时间没更了,因为一直在思索,应该写点什么,真的是无比纠结。这一回,就给大家分享一款简便好用的,小编自制的土晾时间轴。附上XML预览图
- 本文实例为大家分享了Android快速实现断点续传的具体代码,供大家参考,具体内容如下1.导入依赖compile 'com.loop
- 1、cmd指令,进入.svn目录,找到wc.db文件 sqlite 3 打开2、 对 svn源代码目录 右键, clean up, 稍等1至