.NET 8 WinForms中Application.SetHighDpiMode()始终返回false求助
我正在测试优化WinForms应用显示渲染的方案,之前通过应用设置布尔值,启动时决定是否调用SetProcessDPIAware()。目前发现仅能通过在csproj文件的<PropertyGroup>中添加<ApplicationHighDpiMode>xxxx</ApplicationHighDpiMode>(xxxx可选值:DpiUnaware、SystemAware、PerMonitor、PerMonitorV2、DpiUnawareGdiScaled)修改渲染方式。
我希望通过代码程序化更改DPI处理逻辑,于是在Program.cs中添加了以下代码:
public static string DpiVal = ""; ApplicationConfiguration.Initialize(); <ApplicationHighDpiMode>DpiUnawareGdiScaled</ApplicationHighDpiMode> HighDpiMode dpi = (HighDpiMode)Properties.Settings.Default.DpiMode; Application.EnableVisualStyles(); bool status = Application.SetHighDpiMode(dpi); DpiVal = string.Format("SetHighDpiMode({0}) returned {1}. Current HighDpiMode: {2}.", dpi, status, Application.HighDpiMode.ToString()); Application.Run(new Form1());
测试时在主窗体打印DpiVal,发现SetHighDpiMode始终返回false,HighDpiMode属性从未改变,示例输出:
SetHighDpiMode(PerMonitorV2) returned false. Current HighDpiMode: SystemAware.
根据文档说明,仅在清单(显式指定或通过csproj)设置HighDpiMode时该方法才返回false,但即使无清单或用默认清单(且csproj未设置ApplicationHighDpiMode),结果仍为false。
请问我操作有误吗?附加问题:如何在清单文件中指定ApplicationHighDpiMode?是否有类似csproj中<PropertyGroup>的特殊组?
一、操作错误点
- 代码混入非C#语法内容:
ApplicationConfiguration.Initialize();之后的<ApplicationHighDpiMode>DpiUnawareGdiScaled</ApplicationHighDpiMode>是csproj的XML配置语法,不属于C#代码,不仅会引发编译错误,还会打乱DPI模式设置的执行顺序。 - 方法调用顺序错误:
Application.SetHighDpiMode必须在ApplicationConfiguration.Initialize()和Application.EnableVisualStyles()之前调用。因为ApplicationConfiguration.Initialize()内部会根据清单或csproj配置初始化高DPI模式,后续再调用SetHighDpiMode会被直接忽略,导致返回false。
正确的代码顺序如下:public static string DpiVal = ""; // 优先设置高DPI模式 HighDpiMode dpi = (HighDpiMode)Properties.Settings.Default.DpiMode; bool status = Application.SetHighDpiMode(dpi); // 再执行初始化和样式启用 ApplicationConfiguration.Initialize(); Application.EnableVisualStyles(); DpiVal = string.Format("SetHighDpiMode({0}) returned {1}. Current HighDpiMode: {2}.", dpi, status, Application.HighDpiMode.ToString()); Application.Run(new Form1()); - 默认清单的隐性配置:新版.NET的WinForms项目默认会启用
SystemAware模式,即使你未手动修改csproj或清单,这个默认设置也会阻止SetHighDpiMode生效。解决方法是在csproj中显式设置<ApplicationHighDpiMode>DpiUnaware</ApplicationHighDpiMode>,或者在清单中不指定高DPI模式,给代码留出覆盖空间。
二、清单文件中指定ApplicationHighDpiMode的方法
应用清单文件(通常为app.manifest)中,需在<assembly>节点下的<application>节点内添加<windowsSettings>配置,没有类似csproj的<PropertyGroup>特殊组,具体格式如下:
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <!-- 基础高DPI设置 --> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> <!-- PerMonitorV2模式需额外添加此行 --> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> </windowsSettings> </application> </assembly>
各模式对应的清单配置值:
DpiUnaware:<dpiAware>false</dpiAware>SystemAware:<dpiAware>true</dpiAware>PerMonitor:<dpiAware>true/PM</dpiAware>PerMonitorV2:同时添加<dpiAware>true/PM</dpiAware>和<dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>DpiUnawareGdiScaled:<dpiAware>false/PM</dpiAware>
注意:若同时在csproj和清单中设置高DPI模式,csproj的配置优先级更高,会覆盖清单中的设置。
内容的提问来源于stack exchange,提问作者Borjan

