我将设置这个问题并自己回答,以便其他人可以更轻松地搜索并找到正确的答案。我不得不用谷歌搜索几个小时并从多个来源编译最终结果......
所以问题是——如何在 ClickOnce 场景(WPF,特别是 c#)中启用 Per-Monitor v2 DPI 感知?
Win 10 Creators Update (1703) 中添加了 Per-Monitor v2。 ClickOnce 众所周知不支持 DPI 感知应用程序清单 file, 像这样 https://stackoverflow.com/a/43234355/392048.
首先,任何想要喊叫的人 - 只是针对 .NET 4.6.2,默认情况下启用每个显示器 DPI 感知 - 这根本不是真的。
.NET 4.6.2 中默认启用的是幕后的样板代码 - 窗口声明代码中相当讨厌的 C++ 挂钩,以启用对每个显示器 dpi 感知的支持。
您仍然必须通过 app.manifest 声明您支持每个显示器 dpi 感知,但 ClickOnce 不支持它。
(请注意,早期版本的 .NET 将不支持每个显示器 dpi 感知,即使使用应用程序清单也是如此,除非您手动添加样板代码 https://msdn.microsoft.com/en-us/library/windows/desktop/ee308410(v=vs.85).aspx)
现在给出答案:
- 确保您的项目目标.NET 4.6.2。 (最简单的方法是使用 Visual Studio 2017)
- 在程序集属性中禁用 DPI 感知。相信我,我们稍后将在代码中重新启用它。为此,请打开AssemblyInfo.cs在你的项目下特性节点(展开里面的扳手图标解决方案浏览器,通常在右侧)。将以下代码添加到最后一行:
[assembly: DisableDpiAwareness]
。 (这将需要一个using System.Windows.Media;
语句,只需单击将鼠标悬停在红色波浪线上时出现的灯泡并添加建议的 using 语句)
- Add an app.manifest file and declare support for Win 10 and other OS versions. Right-click your project in SolutionExplorer -> add -> new item -> Application manifest file. Open the created manifest file and in the middle there is a section with OS versions, uncomment them as such:
Do not uncomment the section about DPI awareness (a bit further down)! ClickOnce will throw errors if you do.
-
现在,您的项目中的某处需要以下 C# 代码,我建议为此创建一个新的静态类:
internal static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool SetProcessDpiAwarenessContext(int dpiFlag);
[DllImport("SHCore.dll", SetLastError = true)]
internal static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);
[DllImport("user32.dll")]
internal static extern bool SetProcessDPIAware();
internal enum PROCESS_DPI_AWARENESS
{
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
}
internal enum DPI_AWARENESS_CONTEXT
{
DPI_AWARENESS_CONTEXT_UNAWARE = 16,
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = 17,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = 18,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = 34
}
}
-
最后一部分是调用上述 p/invoke 方法并声明 dpi 感知支持。我们需要在任何其他代码运行之前执行此操作。为此,请右键单击app.xaml in 解决方案浏览器并选择View Code
。然后添加这段代码:
protected override void OnStartup(StartupEventArgs e)
{
if (Environment.OSVersion.Version >= new Version(6, 3, 0)) // win 8.1 added support for per monitor dpi
{
if (Environment.OSVersion.Version >= new Version(10, 0, 15063)) // win 10 creators update added support for per monitor v2
{
NativeMethods.SetProcessDpiAwarenessContext((int)NativeMethods.DPI_AWARENESS_CONTEXT.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else NativeMethods.SetProcessDpiAwareness(NativeMethods.PROCESS_DPI_AWARENESS.Process_Per_Monitor_DPI_Aware);
}
else NativeMethods.SetProcessDPIAware();
base.OnStartup(e);
}
确保代码的其余部分正确处理 DPI。从 .NET 4.6.2 开始,您可以使用OnDpiChanged
事件和VisualTreeHelper.GetDpi()
method.
Enjoy :)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)