WinForms:如何修复在高DPI、多显示器环境(PerMonitorV 2)中使用不同分辨率/缩放比例的表单缩放错误

zf2sa74q  于 2023-08-07  发布在  其他
关注(0)|答案(2)|浏览(206)

在Winforms应用程序中,我遵循how-to-write-winforms-code-that-auto-scales-to-system-font-and-dpi-settings.Net Framework high-dpi support中的一般指导来启用PerMonitorV 2 DPI Scaling。我在Windows 10周年更新(1607)后的系统上使用.NET Framework 4.8,以利用最新的高DPI支持功能。
如果应用程序在主显示器或与主显示器具有相同缩放比例的任何显示器上启动,DPI缩放看起来很好,但是如果任何窗体(应用程序的主窗体或二级顶级窗体)首次显示在具有与主显示器不同DPI的显示器上,则缩放比例完全错误。例如,如果应用程序在4k/250%缩放比例的笔记本电脑屏幕上启动(其他四个显示器为1920 x1080/100%缩放比例),则窗体在4k屏幕上以1:1缩放比例显示,并在该屏幕上显示为1平方英寸(只有标题和菜单栏正确缩放):Image Showing Bad Scaling的函数。
此问题似乎是由于在这些情况下未正确设置窗体的 CurrentAutoScaleDimensions 而导致的。它们似乎被设置为
主屏幕
的当前“尺寸”,而不是正在显示表单的屏幕。但是,如果表单首先显示在主屏幕上,然后移动到具有不同DPI的屏幕上,则 CurrentAutoScaleDimensions 会正确更新以反映目标屏幕的实际DPI,并且表单会正确缩放。因此,例如,如果我将主屏幕设置为4k/250%屏幕,然后在1920 x1080/100%屏幕上启动应用程序,则 CurrentAutoScaleDimensions(错误地)被设置为4k/250%屏幕的尺寸,并导致Form过度缩放。但是,如果我在主4k/250%屏幕上启动应用程序,它在第一次显示时会正确缩放,然后在拖动到其他显示器(并返回)时也会正确缩放。总而言之,第一次显示窗体时,CurrentAutoScaleDimensions 似乎总是设置为主显示器尺寸,而不是显示窗体的屏幕尺寸。
有人知道这种情况的补救措施吗?

voase2hg

voase2hg1#

我能想到的最好的解决方案是强制应用程序总是在主屏幕上启动,而不管它是从哪个屏幕启动的。这似乎解决了主窗体初始缩放的所有问题,并且在显示器之间拖动时的所有后续缩放似乎都很好:

  1. public Form1()
  2. {
  3. this.Font = SystemFonts.IconTitleFont;
  4. // Force the main Form of the app to always open on the primary screen
  5. // to get scaling to work.
  6. this.Location = Screen.PrimaryScreen.WorkingArea.Location;
  7. this.StartPosition = FormStartPosition.Manual;
  8. InitializeComponent();
  9. ...

字符串
对于应用程序生成的辅助窗体,我发现如果我首先在主屏幕上显示它们,然后隐藏并在包含应用程序主窗体(我希望它们显示的位置)的屏幕上重新显示它们,它们可以正确缩放。在某些情况下,我发现只调用 f.PerformLayout() 就足够了,而不是在主屏幕上实际显示表单,但这并不是在所有情况下都有效。

  1. private void secondFormToolStripMenuItem_Click(object sender, EventArgs e)
  2. {
  3. FormExtra f = new FormExtra(this);
  4. // First display the Form on the primary screen to make scaling correct
  5. f.StartPosition = FormStartPosition.Manual;
  6. f.Location = Screen.PrimaryScreen.WorkingArea.Location;
  7. f.Show();
  8. // Then hide it and move it where we really want it
  9. f.Hide();
  10. f.StartPosition = FormStartPosition.CenterParent;
  11. f.ShowDialog();
  12. }


这种解决方案并不理想,因为表单会在另一个屏幕上短暂 Flink ,这看起来相当笨拙。然而,这个解决方案似乎确实导致了应用程序中所有窗体的正确缩放,而不管应用程序在哪个监视器上启动。到目前为止,我已经在两种不同的多显示器配置上测试了它。

展开查看全部
14ifxucb

14ifxucb2#

我也有同样的问题。我的主屏幕是4K,在Windows中缩放到175%。我的第二个屏幕是2560x1440,比例为125%。当在用户之前拖动到的位置打开窗体时,如果是在辅助屏幕上,则窗体太大。只要用户移动窗体,即使是很小的量,屏幕也会调整大小以正确缩放。
我所做的是补充:
Me.Left = Me.Left + 1(vb.net,但我怀疑C#是类似的)到窗体Load Sub

  1. Private Sub frmSelectNewIx_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  2. Me.Left = Me.Left + 1
  3. AddHandler LocationChanged, AddressOf SaveNewFormPosition ' In a module to save the forms new position using a timer.

字符串
......
这迫使屏幕移动,自动缩放开始,没有明显的视觉故障。

相关问题