【发布时间】:2015-11-03 23:21:48
【问题描述】:
我在使用 C# 编写的非常复杂的 WinForms 应用程序时遇到了一点问题。我希望应用程序在 DPI 更改时让 Windows 自动缩放,但我仍然需要挂钩 WM_DPICHANGED 事件以缩放一些自定义绘制的文本。
困境是,如果我让应用程序 DPI 不知道 WM_DPICHANGED 消息永远不会在 DefWndProc 中被截获,并且永远无法检索到正确的 DPI 比例,但表单会以我想要的方式“自动缩放”。但是如果我让应用程序 DPI Aware 则 WM_DPICHANGED 消息被截获并且可以计算正确的 DPI 但表单不会“自动缩放”。
正如我所说,该应用程序非常复杂,并且使用了大量第三方控件,因此我无法花时间在 WPF 中重新编写应用程序或尝试自己扩展应用程序。
如何让应用拦截 WM_DPICHANGED 消息、计算正确的 DPI 并仍然允许 Windows 管理表单缩放?
程序.cs:
static class Program
{
[STAThread]
static void Main()
{
if (Environment.OSVersion.Version.Major >= 6)
{
// If the line below is commented out then the app is no longer DPI aware and the
// WM_DPICHANGED event will never fire in the DefWndProc of the form
int retValue = SetProcessDpiAwareness(ProcessDPIAwareness.ProcessPerMonitorDPIAware);
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private enum ProcessDPIAwareness
{
ProcessDPIUnaware = 0,
ProcessSystemDPIAware = 1,
ProcessPerMonitorDPIAware = 2
}
[DllImport("shcore.dll")]
private static extern int SetProcessDpiAwareness(ProcessDPIAwareness value);
}
Form1.cs:
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case 0x02E0: //WM_DPICHANGED
{
int newDpi = m.WParam.ToInt32() & 0xFFFF;
float scaleFactor = (float)newDpi / (float)96;
}
break;
}
base.DefWndProc(ref m);
}
更新: 我正在使用具有多显示器设置的 Windows 10。所有显示器都是相同型号,基本分辨率为 1920x1080。我使用显示设置将我的一台显示器设置为 125% 的尺寸。
【问题讨论】:
-
如果您要否决这个问题,至少要说明原因,以便改进。
-
@ToddSprang - 我已经看到了,但是这个例子是针对 WPF 的,并且 xaml 表单是使用我不熟悉和/或不知道如何转换为 WinForms 代码的方法重新绘制的。默认情况下,WPF 支持 DPI。
-
这里是winforms:emoacht.wordpress.com/2013/10/30/…
-
@ToddSprang - 该链接看起来很有希望,但我正在编写的应用程序中有很多控件,因此这可能会或可能不会与大量额外代码一起使用。我会试一试,但我想看看是否可以通过让 Windows 完成所有调整大小的工作来获得更简单的方法。