WPF中为Popup和ToolTip使用WindowMaterial特效 win10/win11

news/2024/10/15 19:37:57

先看效果图:

FluentToolTipFluentPopup

大致思路是:通过反射获取Popup内部的原生窗口句柄,然后通过前文已经实现的WindowMaterial类来应用窗口特效;对于ToolTip,为了保持其易用性,我使用了附加属性+全局样式的方式来实现,ToolTip也是一个特殊的Popup.
前文链接:WPF 模拟UWP原生窗口样式——亚克力|云母材质、自定义标题栏样式、原生DWM动画 (附我封装好的类)
本文的Demo:

TwilightLemon/WindowEffectTest: 测试win10/11的模糊效果 (github.com)

一、获取原生窗口句柄

通过查阅.NET源码得知,Popup内部通过一个类型为PopupSecurityHelper的私有字段_secHelper来管理窗口hWnd,并且在创建完成之时会触发Popup.Opened事件。
通过反射来获取窗口句柄:

const BindingFlags privateInstanceFlag = BindingFlags.NonPublic | BindingFlags.Instance;
public static IntPtr GetNativeWindowHwnd(this Popup popup)
{//获取Popup内部的_secHelper字段Infovar field = typeof(Popup).GetField("_secHelper", privateInstanceFlag);if (field != null){//获取popup的_secHelper字段值if (field.GetValue(popup) is { } _secHelper){//获取_secHelper的Handle属性Infoif (_secHelper.GetType().GetProperty("Handle", privateInstanceFlag) is { } prop){if (prop.GetValue(_secHelper) is IntPtr handle){//返回句柄return handle;}}}}//未找到return IntPtr.Zero;
}

同样地,能在ToolTip内部找到私有字段_parentPopup

public static IntPtr GetNativeWindowHwnd(this ToolTip tip)
{var field=tip.GetType().GetField("_parentPopup", privateInstanceFlag);if (field != null){if(field.GetValue(tip) is Popup{ } popup){return popup.GetNativeWindowHwnd();}}return IntPtr.Zero;
}

二、应用WindowMaterial特效

有了窗口句柄那么一切都好办了,直接调用我封装好的WindowMaterial类,如果你想了解更多请查看前文。

public static void SetPopupWindowMaterial(IntPtr hwnd,Color compositionColor,MaterialApis.WindowCorner corner= MaterialApis.WindowCorner.Round)
{if (hwnd != IntPtr.Zero){int hexColor = compositionColor.ToHexColor();var hwndSource = HwndSource.FromHwnd(hwnd);//----MaterialApis.SetWindowProperties(hwndSource, 0);MaterialApis.SetWindowComposition(hwnd, true, hexColor);//----
        MaterialApis.SetWindowCorner(hwnd, corner);}
}

根据微软的设计规范,这里默认对普通Popup使用圆角,对ToolTip使用小圆角,使用亚克力材质并附加compositionColor。
在github中获取完整的WindowMaterial.cs,我可能会不定期地更新它:WindowEffectTest/WindowMaterial.cs at master · TwilightLemon/WindowEffectTest (github.com)

如果你想使用Mica或MicaAlt等材质则将上面框起来的代码替换为:

MaterialApis.SetWindowProperties(hwndSource, -1);
MaterialApis.SetBackDropType(hwnd, MaterialType.Mica);
MaterialApis.SetDarkMode(hwnd, isDarkMode: true);

三、没错我又封装了一个即开即用的类

在Demo中查看封装好的类:WindowEffectTest/FluentPopup.cs at master · TwilightLemon/WindowEffectTest (github.com)

使用FluentPopup

<local:FluentPopup x:Name="testPopup"StaysOpen="False"Placement="Mouse"Background="{DynamicResource PopupWindowBackground}"><Grid Height="120" Width="180"><TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">nihao </TextBlock></Grid>
</local:FluentPopup>

其中,Background属性是我自定义的一个依赖属性,只允许使用SolidColorBrush,用于设置亚克力特效的CompositionColor。
如果你希望像Demo中那样让Popup失焦自动关闭,可以设置StaysOpenFalse,在后台打开Popup时使用:

private async void ShowPopupBtn_Click(object sender, RoutedEventArgs e)
{await Task.Yield();testPopup.IsOpen = true;
}

关于为什么要加上await Task.Tield(),可以看看吕毅大佬的文章:一点点从坑里爬出来:如何正确打开 WPF 里的 Popup? - Walterlv

在全局内使用FluentToolTip

我自定义了一个附加属性FluentTooltip.UseFluentStyle,你只需要在App.xaml中设置即可全局生效: 这里的PopupWindowBackgroundForeColor是我自定义的颜色资源,你可以根据自己的需要来设置。
同样地Background仅支持SolidColorBrush

<Style TargetType="{x:Type ToolTip}"><Setter Property="local:FluentTooltip.UseFluentStyle"Value="True" /><Setter Property="Background"Value="{DynamicResource PopupWindowBackground}" /><Setter Property="Foreground"Value="{DynamicResource ForeColor}" />
</Style>

这样你就可以方便地创建一个Fluent风格的ToolTip了:

<Button ToolTip="xxxxx"/>

 

参考链接

Popup.cs at Dotnet Source

ToolTip.cs at Dotnet Source

一点点从坑里爬出来:如何正确打开 WPF 里的 Popup? - Walterlv

WPF 模拟UWP原生窗口样式——亚克力|云母材质、自定义标题栏样式、原生DWM动画 (附我封装好的类) - TwilightLemon

 

  本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名TwilightLemon(https://blog.twlmgatito.cn),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

文章及其代码仓库可能不时更新,查看原文:WPF中为Popup和ToolTip使用WindowMaterial特效 win10/win11 - Twlm's Blog (twlmgatito.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/71944.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

数据采集与融合技术第一次作业

作业1 1)用requests和BeautifulSoup库方法定向爬取给定网址(http://www.shanghairanking.cn/rankings/bcur/2020 )的数据,屏幕打印爬取的大学排名信息。 import urllib.request from bs4 import BeautifulSoup# 定义 URL url = http://www.shanghairanking.cn/rankings/bcu…

『模拟赛』多校A层冲刺NOIP2024模拟赛07

『模拟赛记录』多校A层冲刺NOIP2024模拟赛07Rank 一般,挂大分场。A. 限速(speed) 签。 直接跑一棵最小生成树出来,然后 dfs 一遍,如果有边权不小于 \(k\) 的就给答案加上绝对值的差,若没有则再遍历一遍所有边找到与 \(k\) 之差绝对值最小的边插进去就行,答案就是这个绝对…

数据采集第二次作业

数据采集实践第二次作业 目录点击展开/收起作业①:定向爬取7日天气预报 作业②:定向爬取股票相关信息 作业③:定向爬取中国大学2021主榜信息 总结● 码云链接 作业1 xh102202145/crawl_project作业①:定向爬取7日天气预报 1.1 实验要求 在中国气象网(http://www.weather.…

全链路营销|基于事件驱动的流程编排系统 策略中心系统

全链路营销|基于事件驱动的流程编排系统 https://mp.weixin.qq.com/s/RHXyGaGyp_CK7FJPDqS3Cg 全链路营销|基于事件驱动的流程编排系统 原创 西赞 阿里云开发者 2024年10月14日 08:30 浙江 阿里妹导读本文主要介绍了 AE 策略中心的技术方案选型与落地实战。项目背景 全链路营…

去除 iPhone 设置右上角强制升级红色数字方法

iPhone 强制用户升级在设置右上角有红色数字提示,即使关闭了自动升级也清不掉。可以用快捷指令伪造一个设置的快捷方式来替代原生设置图标打开快捷指令,点击 + 新建快捷指令选择“打开App”点击 App标签,选取“设置”然后点击当前正在创建的快捷指令顶端的 “打开App”,自定…

免费又强大!这五款报表工具你一定要试试

1. 山海鲸可视化报表 简介:山海鲸报表是一款完全免费的专业报表工具,旨在帮助企业和个人用户轻松创建、管理、分享各类数据报表。该工具提供了免费一站式数据处理和展示平台,具备灵活的定制化能力,能够满足各种行业的报表需求,不仅能够处理各式复杂报表,而且提供了非常丰…

kmp算法关于从0开始和从1开始

暴力匹配BF算法从零开始: **** kmp算法从零开始:从1开始王道上面标准代码 如何记忆? 就假设s=“abc”, t=“a”,带入进去比较下。

上海交大开源超逼真声音克隆 TTS;微软探索音生图 AI 模型丨 RTE 开发者日报

这里是 「RTE 开发者日报 」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文章 」、「有看点的 会议 」,但内容仅代表编辑的个人观点,欢迎大家…