混合使用WPF和WinForms的项目DPI感知

12
我有一个使用winforms和WPF的C#程序,在高DPI环境下无法正常工作。如果我从解决方案中删除所有WPF项目并运行它,它会正常缩放,但只要我再添加任何wpf(必需的功能),缩放就会失败,UI变得无法使用。
这似乎是先前SO问题的完全相同问题:混合WinForms和WPF应用程序中的.NET 3.5 DPI缩放在DPI下正确缩放WinForms的问题 我按照这些问题上的建议尝试添加了清单文件和提供的dpi感知代码。
我还将项目升级到.net framework 4.6.1(从4.0),并包括app.config设置:<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" /> 这确实影响了程序的主外壳(因此不再以小窗口加载所有控件挤在一起,而是以最大化打开主程序窗口并正常显示)。但是,当我从主窗口进入任何winforms子窗体或插件时,缩放就会失败。
当我进入任何WPF子窗体或插件,或返回到主屏幕时,它们会正确呈现。只有winforms功能无法正确缩放。
有人有任何想法如何在高DPI下正常缩放混合winforms / WPF项目吗?
提前感谢您。

如果您认为这是更好的方法,那就好。我发布了一个新问题,因为我认为我的问题不同,因为他们的解决方法对我没有起作用。 - Anya Hope
4个回答

10

当WPF加载到项目中时,它会将进程提升为系统DPI感知。为了绕过这个问题,首先需要: 1)在入口程序集的命名空间声明之前设置 [assembly: DisableDpiAwareness] 属性 2)可以在项目中添加一个app.manifest文件,并添加以下内容:

 <asmv3:windowsSettings
 xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
       <dpiAware>true/PM</dpiAware> 
 </asmv3:windowsSettings>

这应该能使你的WinForms和WPF内容在正确的目标DPI下呈现。(然而,如果你有不同DPI的多显示器设置,则会导致缩放失败。)

这是对引用问题“https://dev59.com/2mIk5IYBdhLWcg3wI7AF”的回答,但我已经说过对我无效。 - Anya Hope
抱歉,你是对的。我没有注意到。不幸的是,在我尝试使用<dpiAware>配置设置时,我确实尝试了所有可能的值,但很遗憾都没有起作用。 - Anya Hope
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - rohit21agrawal
我终于又看了一下这个问题。我得向你道歉,因为我当时真的太蠢了。我一直把"[assemby: DisableDpiAwareness]"属性放错了位置。当我把它放在我的入口类命名空间上面时,问题完全解决了。我真希望我能事后再支付赏金。 - Anya Hope
我没有像@AnyaHope那样成功。我有一个针对.NET 4.6.1的Windows Forms应用程序。无论我把[assemby: DisableDpiAwareness]放在哪里,甚至是在AssemblyInfo.cs中,它都没有任何视觉效果。我在清单中使用了相同的设置,甚至在app.config中添加了EnableWindowsFormsHighDpiAutoResizing设置。在GitHub上找到一个实际可行的演示将是很好的。 - Frank Hoffman
显示剩余4条评论

4
如果您没有清单文件,因为您是WinForms应用程序而不是WPF应用程序,则必须通过AssemblyInfo.cs进行更改。由于它是相反的方向,因此您必须禁用DPI感知以使世界保持同步,而不是像上面的WPF方法那样启用它。
在AssemblyInfo.cs中添加以下行。
[assembly: System.Windows.Media.DisableDpiAwareness]

我的问题被标记为此问题的重复,但实际上并不是真正的重复,因为我有一个使用WPF组件的WinForms应用程序,而不是相反。我添加这个答案是为了像我一样因错误原因被导向到这里的人。


当我开始时,我的项目正是这样的。基于Winforms,使用WPF组件,所以我很高兴这里有这个东西,可以帮助其他处于同样情况下的人。感谢您的发布。 - Anya Hope
非常感谢!我花了3个小时来处理所有的app.manifest和config设置,但什么都没起作用。最后我把它们全部删除,只是简单地添加了这个,现在应用程序可以正确缩放了。非常感谢您的发布。需要明确的是,我的应用程序是一个Win Form应用程序,其中包含一些WPF控件。 - gigi

2

我的同事最终解决了这个问题。由于在此项目中,没有任何配置设置等能起作用,因此我们尝试移除winforms shell并将其替换为WPF shell。一旦主要shell项目在WPF中重新编写,所有的“插件”就以正确的DPI比例显示出来了。

我知道这不是最好的解决方法,因为它涉及对现有代码的重写,但对于我们而言,这是唯一能解决问题的方法。


0

非常感谢您的回答@rohit21agrawal!

我曾经有一个类似的复杂Win Forms解决方案,每当我在WeifenLuo的DockPanelSuite中打开一个停靠窗体时,该窗体会重新调整大小并破坏整个GUI。

现在,在尝试了几年不同的方法(没有一个有效)之后,您拯救了我的生命!

除了您的答案外,还有其他开发人员想知道如何实现您的解决方案:

  1. a)(我的项目目标为.NET Framework 4.7.2)
  2. b)(所有我的窗体都设置为AutoScaleMode = Font)
  3. 在您的WinForms项目中,添加对WindowsBase的引用(应该是程序集列表中倒数第三个条目)
  4. 将“[assembly: System.Windows.Media.DisableDpiAwareness]”添加到您的AssemblyInfo.cs
  5. 添加“
<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
    <dpiAware>true/PM</dpiAware>
  </windowsSettings>
</application>
将代码 "<assembly>…</assembly>" 插入到您的 app.manifest 文件中的父级部分。
在我的情况下,这个方法非常有效 :-) 我能够在不同的显示器之间移动窗体(一个4K屏幕和175%缩放字体,另一个全高清屏幕和125%缩放字体),并且它会立即重绘/重新渲染所有控件!
再次感谢! Cordt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接