使 WinForms 和 WPF 支持高 DPI(每显示器缩放/2018年)

本文介绍了如何使WinForms和WPF应用支持高DPI,包括在不同显示器之间保持清晰显示。针对WPF,文章详细说明了在应用程序清单文件中启用Per Monitor DPI awareness的步骤,以及对.NET Framework 4.6.2以下版本的额外修改。对于WinForms,文章指导了声明Windows 10兼容性,启用每显示器DPI感知,以及处理与DPI相关的像素值。

前言

WinForms 和 WPF 都支持高 DPI,但是在默认情况下,不是未开启,就是效果不尽人意。例如,默认情况下,WPF 程序在单个高分屏上表现良好,但是如果把窗口拖动到不同的窗口上去,就会变得模糊。

关于不同的 DPI 缩放(感知)类型,请在此查看:https://docs.microsoft.com/zh-cn/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows

环境

  • Windows 10 1809
  • .NET Framework 4.7.2
  • Visual Studio 2017 15.9.4

所用环境是发文时最新稳定版。条件所限,其他环境请自行测试。

WPF

默认情况下,WPF 只支持单显示器的 DPI 缩放,在移动到缩放比例不同的显示器时,仍使用系统缩放,导致模糊。下面介绍开启Per monitor DPI awareness的方法。

1. 在 app.manifest 中开启 Per monitor DPI awareness

为了支持 Per monitor DPI awareness,需要修改 app.manifest 文件。如果你的项目没有这个文件,请新建应用程序清单文件,名称保持默认的 app.manifest

找到清单文件中的这一段:

  <!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
       自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
       选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
       在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->

  <!--<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>-->

可以看到提到了 DPI 感知,但其实上面这部分内容已经有点过时。
我们把下半部分替换成:

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    </windowsSettings>
  </application>

2. 修改 App.config (4.6.2 及以上不需要)

对于 .NET Framework 4.6.2 以下的版本,还需要修改 App.config 文件。下面是未更改的原始文件。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
    </startup>
</configuration>

将其更改为

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
    </startup>
  <runtime>
    <AppContextSwitchOverrides value = "Switch.System.Windows.DoNotScaleForDpiChanges=false"/>
  </runtime>
</configuration>

请自行比较不同部分。

3. 测试应用

运行程序,在不同缩放比例的显示器之间拖动。

正常情况下,纯 WPF 部分应该完美缩放,其余部分可能无法完美支持。请根据您的应用自行取舍。

更多内部请查看文后的参考资料。

WinForms

WinForms 的设置与 WPF 有所不同,不能按照 WPF 的方式进行设置。

1. 声明与 Windows 10 的兼容性

app.manifest 文件中找到下面部分,并按示例取消注释。如果你的项目没有这个文件,请按上面的方法创建。

      <!-- Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

2. 启用每显示器 DPI 感知

修改 App.config,添加下面内容

<System.Windows.Forms.ApplicationConfigurationSection>
  <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>

根据微软给出的文档,

在以前版本的 .NET Framework 中,你可以使用清单来添加高 DPI 支持。 不再建议使用此方法,因为它会替代在 app.config 文件中定义的设置。

3. 测试应用

WinForms 对高 DPI 的支持更差。通过 API 获取到的像素值是与 DPI 相关的。也就是说,同样窗口大小,在不同显示器上会获取到不同的像素值。你必须手动处理。

参考资料

https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI

https://docs.microsoft.com/zh-cn/dotnet/framework/winforms/high-dpi-support-in-windows-forms

<think>好的,我需要帮助用户找到关于DPI缩放替代方案的信息。首先,我需要理解DPI缩放是什么。DPI指的是每英寸点数,通常在分辨率屏幕上使用,以确保界面元素不会显得过小。Windows系统有内置的DPI缩放功能,但可能存在兼容性问题,尤其是在旧应用程序中。 用户提到他们参考的引用内容涉及GDIGDI+,这可能与图形渲染有关。GDI是较旧的图形接口,而GDI+是其改进版,提供了更好的对象模型性能。但DPI环境下,这些技术可能需要调整才能正确缩放。 首先,我应该考虑系统级的DPI设置替代方案。比如,Windows允许每个应用程序单独设置DPI缩放,覆盖系统设置。这可以通过兼容性选项卡中的“DPI缩放替代”选项实现,用户可能已经知道这一点,但需要其他方法。 接下来是应用程序层面的解决方案。使用DPI感知模式,比如在清单文件中声明应用程序支持DPI感知,这样系统就不会进行缩放,而是由应用程序自己处理。这对于开发人员来说是重要的,但用户可能需要现成的工具或方法。 然后是第三方工具。例如,Microsoft的Desktop Window Manager(DWM)可以协助缩放,但效果可能因应用程序而异。还有像Custom Resolution Utility(CRU)这样的工具,允许自定义分辨率缩放设置,可能提供更灵活的控制。 框架库的更新也很重要。WPFUWP原生支持DPI,而WinFormsMTA需要在.NET框架4.7及以上版本通过app.config设置启用PerMonitorV2模式。对于使用GDI+的旧项目,可能需要手动调整绘图代码,使用GetDpiForMonitor等API获取当前DPI缩放元素。 另外,用户可能需要了解如何测试调试DPI问题。工具比如Microsoft的Remote Desktop可以模拟不同DPI环境,帮助测试应用程序的缩放表现。 最后,用户可能对具体实现步骤感兴趣,比如如何在代码中处理DPI变化,或者如何修改现有项目以支持DPI。引用中的Font.Height属性可能用于计算行间距,在DPI下需要根据DPI缩放因子调整这些值,确保布局正确。 总结,我需要将这些信息分点整理,确保符合格式要求,使用正确的中文表达,并生成相关问题。同时,注意引用标记的正确使用,尽管用户提供的引用可能与DPI无直接关系,但可能需要调整或忽略,除非有更相关的引用内容。</think>关于DPI缩放的替代解决方案,以下是系统级的实现方式常见技术方案: ### 一、系统级DPI设置替代方案 1. **Windows DPI缩放覆盖** 在应用程序属性中启用"替代DPI缩放行为",强制使用系统缩放算法。可通过注册表实现: ```python # 设置应用程序.exe的DPI缩放模式 import winreg key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers") winreg.SetValueEx(key, "C:\\Path\\App.exe", 0, winreg.REG_SZ, "HIGHDPIAWARE") ``` 2. **DPI虚拟化技术** 通过`SetProcessDpiAwareness`API设置进程级DPI感知模式: ```cpp #include <ShellScalingAPI.h> SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); ``` ### 二、应用程序层解决方案 1. **WPF矢量渲染方案** 使用Viewbox容器实现自动缩放: ```xml <Viewbox Stretch="Uniform"> <Canvas Width="1920" Height="1080"> <!-- 原始设计尺寸内容 --> </Canvas> </Viewbox> ``` 2. **WinForms动态缩放** 通过DPI缩放因子调整控件尺寸: ```csharp float dpiScale = this.DeviceDpi / 96f; button1.Width = (int)(originalWidth * dpiScale); button1.Height = (int)(originalHeight * dpiScale); ``` ### 三、第三方工具方案 1. **Microsoft DPI Scaling Enabler** 通过修改注册表强制启用DPI感知: ```powershell Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name "Win8DpiScaling" -Value 1 ``` 2. **第三方渲染引擎** 使用跨平台框架如Electron或Qt,其内置DPI处理机制更完善: ```javascript // Electron主进程配置 app.commandLine.appendSwitch('high-dpi-support', 'true'); app.commandLine.appendSwitch('force-device-scale-factor', '1.5'); ``` ### 四、图形接口优化 对于GDI+应用程序,需手动处理DPI缩放: ```csharp Graphics g = e.Graphics; float dpiScale = g.DpiX / 96f; Rectangle scaledRect = new Rectangle(0, 0, (int)(100*dpiScale), (int)(50*dpiScale)); g.DrawString("Text", scaledFont, Brushes.Black, scaledRect); ``` 该方案通过动态计算缩放因子,可适配不同DPI显示器[^1]。对于字体渲染,需特别注意使用`Font.GetHeight()`获取适配后的行[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值