首页 > 其他分享 > WPF 修复 ContextMenu 在开启 PerMonitorV2 后所用 DPI 错误

WPF 修复 ContextMenu 在开启 PerMonitorV2 后所用 DPI 错误

时间:2022-09-29 08:22:15浏览次数:90  
标签:控件 ContextMenu 创建 WPF PerMonitorV2 DPI

本文告诉大家如何修复 WPF 的 ContextMenu 在开启 PerMonitorV2 之后,在双屏不同的 DPI 的设备上,在副屏弹出的 ContextMenu 使用了主屏的 DPI 导致缩放错误的问题

关于什么是 PerMonitorV2 请参阅 支持 Windows 10 最新 PerMonitorV2 特性的 WPF 多屏高 DPI 应用开发 - walterlv

开启 PerMonitorV2 的 WPF 应用的 ContextMenu 将在多屏下,需要找到一个关联的屏幕来辅助计算所要显示的坐标。然而在 ContextMenu 创建出来时,是无法知道应该选用哪个屏幕。这就是导致 ContextMenu 视觉效果的 DPI 缩放不对的原因

修复方法就是给 ContextMenu 一个参考的控件,通过此参考控件,可以让 ContextMenu 进行多屏幕不同的 DPI 计算。给 ContextMenu 一个参考的控件的方法有两个

第一个方法是通过将 ContextMenu 设置给所要关联的控件的 ContextMenu 属性上,如此即可让 ContextMenu 弹出的坐标可以根据此关联控件计算。要求关联的控件是在界面布局

            var menu = new ContextMenu
            {
                Name = menuName,
                Style = contextMenuStyle,
                ItemsSource = menuItems,
            };
            canvas.ContextMenu = menu;

但是以上方法存在缺点,那就是对相同的业务逻辑,在 ContextMenu 关闭之前重新赋值,将存在重入问题,重入问题也许导致了某个过程的 ContextMenu 依然由于找不到关联的控件,弹出在左上角。例如以上代码被快速进入两次,第一次的 ContextMenu 对象还没完成弹出,第二次就进入,第二次的 ContextMenu 将会覆盖 canvas 的 ContextMenu 属性,从而让第一次的 ContextMenu 找不到关联的控件,让第一次的 ContextMenu 弹出到左上角,或者计算 DPI 不对

如果采用第一个方法,可以通过缓存 ContextMenu 的方式,代替每次都创建。或者判断当前正在准备弹出 ContextMenu 就不继续创建

第二个方法是设置 ContextMenu 的 PlacementTarget 属性,通过此属性可以让 ContextMenu 关联控件,如以下代码

            var menu = new ContextMenu
            {
                Name = menuName,
                Style = contextMenuStyle,
                ItemsSource = menuItems,
                // Popup 内部不处理显示过程中的 DPI 改变,依赖于创建时要能找到正确的屏幕,
                // 如果什么都不指定,那么创建会创建到主屏,如果实际显示在副屏了,那就会因为 DPI 缩放导致尺寸不对。
                // 
                // 寻找创建时的屏幕时,会寻找 PlacementTarget 和 VisualTreeHelper.GetContainingVisual2D(VisualTreeHelper.GetParent(this)),
                // 这里通过指定 PlacementTarget 确保创建的屏幕正确
                PlacementTarget = canvas,
            };

标签:控件,ContextMenu,创建,WPF,PerMonitorV2,DPI
From: https://www.cnblogs.com/lindexi/p/16733237.html

相关文章

  • WPF 切换主题使用 luna 复古版本
    本文告诉大家如何在WPF里面使用luna等复古主题今天在lsj说他准备优化WPF的程序集时,准备删除luna等程序集时,找到了一段有趣的注释,发现在WPF里面可以通过一些有......
  • 【WPF 】ItemTemplateSelector模板选择器
    WPF的ItemsControl数据绑定中,有时会遇到绑定的数据源是多种类型,并且需要对不同类型使用不同的模板。这个时候就需要用到 ItemTemplateSelector。ItemTemplateSelector......
  • WPF应用图标更改,打包后安装依然显示原来的图标
    前因:更改项目的应用图标重新打包安装,发现桌面快捷方式图标依然没改,将该exe文件发送或者拷贝到桌面还是图标没改;但是,将exe文件拷贝到其它文件夹或者磁盘下,图标显示已经改了;......
  • [WPF] 用CefShap仿制浏览器
    多标签页使用第三方库Dragablz可以很轻易地实现可拖动的标签页,多个标签页通过相同的缓存路径共享会话,两个箭头是切换标签页(仅超出时显示),右上角是窗口按钮。......
  • wpf 使用 Generic Host
    wpf使用GenericHostpublicpartialclassApp:Application{privateIHost_host;publicApp(){_host=newHostBuilder().C......
  • WPF 自定义可拖动标题栏
    要注意,拖拽的地方,需要加背景色,否则DrageMove 将无效MainWindows.xaml<Windowx:Class="Report.MainWindow"xmlns="http://schemas.microsoft.com......
  • WPF 由于系统颜色配置 Mscms 组件损坏启动失败
    本文记录WPF应用程序,因为系统的颜色配置Mscms.dll组件损坏导致应用加载图片失败,从而启动失败的原因和解决方法在WPF应用加载图片时,将会调用到系统的Mscms.dll组件......
  • 在 WPF 中实现融合效果
    1.融合效果融合效果是指对两个接近的元素进行高斯模糊后再提高对比度,使它们看上去“粘”在一起。在之前的一篇文章中,我使用Win2D实现了融合效果,效果如下:不过Win2D......
  • WPF学习 - 动画基础
    1.WPF中的动画(Animation),是一种属性动画。技术上来说,它是让属性从一个值,变化到另一个值的过程。因此,有两条条重要的特性:1.1只能为依赖属性应用动画 1.2动画只......
  • 关于WPF自定义控件OnApplyTemplate不执行,手动调用Template.FindName返回空的问题
    我在wpf项目中手写了一个自定义控件,运行得相当的正常,后续调用时,反复遇到问题,前前后后折腾了好几次代码publicExtendCombox(){Loaded+=(e......