支持 Windows 10 最新 PerMonitorV2 特性的 WPF 多屏高 DPI 应用开发


Windows 10 自 1703 开始引入第二代的多屏 DPI 机制(PerMonitor V2),而 WPF 框架可以支持此第二代的多屏 DPI 机制。

本文将介绍 WPF 框架利用第二代多屏 DPI 机制进行高 DPI 适配的方法。同时,也介绍低版本的 WPF 或者低版本的操作系统下如何做兼容。


本文内容

      • 添加应用程序清单文件
        • 如果你没有 app.config,如何添加?
        • 如果你没有 app.manifest,如何添加?
      • 了解 WPF 清单文件中的 DPI 感知设置
        • DpiAware
        • DpiAwareness
      • 使 WPF 程序支持 Per-Monitor V2 级 DPI 感知
      • WPF 程序在特殊清单设置下的效果
      • 低版本 .NET Framework 和 低版本 Windows 下的 WPF DPI 缩放
        • 参考资料

SetProcessDpiAwareness 或 SetProcessDPIAware 函数,那么就会按照调用此函数的效果来感知 DPI。
  • 包含 true 字符串
    • 当前进程设置为系统级 DPI 感知(System DPI Awareness)。
  • 包含 false 字符串
    • 在 Windows Vista / 7 / 8 中,与什么都不填的效果是一样的。
    • 在 Windows 8.1 / 10 中,当前进程设置为不感知 DPI(Unaware),就算你调用了 SetProcessDpiAwareness 和 SetProcessDPIAware 也是没有用的。
  • 包含 true/pm 字符串
    • 在 Windows Vista / 7 / 8 中,当前进程设置为系统级 DPI 感知(System DPI Awareness)。
    • 在 Windows 8.1 / 10 中,当前进程设置为屏幕级 DPI 感知(Per-Monitor DPI Awareness)。
  • 包含 per monitor 字符串
    • 在 Windows Vista / 7 / 8 中,与什么都不填的效果是一样的。
    • 在 Windows 8.1 / 10 中,当前进程设置为屏幕级 DPI 感知(Per-Monitor DPI Awareness)。
  • 其他任何字符串
    • 在 Windows Vista / 7 / 8 中,与什么都不填的效果是一样的。
    • 在 Windows 8.1 / 10 中,当前进程设置为不感知 DPI(Unaware),就算你调用了 SetProcessDpiAwareness 和 SetProcessDPIAware 也是没有用的。
  • 说明一下,SetProcessDpiAwareness 是新 API,要求的最低系统版本是 Windows 8.1,调用这个才能指定为 Per-Monitor 的 DPI 感知。而 SetProcessDPIAware 是 Vista 开始引入的老 API,没有参数可以传。

    SetProcessDpiAwareness 或 SetProcessDPIAware 函数,那么就会按照调用此函数的效果来感知 DPI。
  • 第一个能识别的感知级别是 system
    • 当前进程设置为系统级 DPI 感知(System DPI Awareness)。
  • 第一个能识别的感知级别是 permonitor
    • 当前进程设置为屏幕级 DPI 感知(Per-Monitor DPI Awareness)。
  • 第一个能识别的感知级别是 permonitorv2
    • 当前进程设置为第二代屏幕级 DPI 感知(Per-Monitor V2 DPI Awareness)。
    • 仅在 Windows 10 (1703) 及以上版本才可被识别
  • 第一个能识别的感知级别是 unaware
    • 当前进程设置为不感知 DPI(Unaware),就算你调用了 SetProcessDpiAwareness 和 SetProcessDPIAware 也是没有用的。
  • Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32) - walterlv

    额外的,如果你的 .NET Framework 版本在 .NET Framework 4.6.2 以下,但操作系统在 Windows 10 及以上,你还需要修改 App.config 文件(在 节点)。

    <runtime>
      
    runtime>
    

    注意:

    1. 这个值要设为 false。(微软官方吐槽:Yes, set it to false. Double negative FTW!)
    2. AppContextSwitchOverrides 不能被设置两次,如果一已经设置了其他值,需要用分号分隔多个值。

    特别说明,当面向 .NET Framework 4.6.2 以下版本编译,但运行于 Windows 10 (1607) 和以上版本时,只需要添加 Switch.System.Windows.DoNotScaleForDpiChanges=false 即可让 WPF 程序处理 Dpi Change 消息,此时 WPF 程序就像高版本的 .NET Framework 中一样能够正常处理多屏下的 DPI 缩放。

    以上,划重点 你并不需要编译为高版本的 .NET Framework 即可获得 Per-Monitor 的 DPI 缩放支持

    Developing a Per-Monitor DPI-Aware WPF Application - Microsoft Docs 了解实现方法。具体是使用 DisableDpiAwareness 特性和 Windows Per-Monitor Aware WPF Sample 中的源码。


    Developing a Per-Monitor DPI-Aware WPF Application - Microsoft Docs
  • WPF-Samples/Developer Guide - Per Monitor DPI - WPF Preview.docx at master · Microsoft/WPF-Samples
  • Application Manifests - Microsoft Docs