使用自定义 ImageListView 控件后出现表单缩小问题

tec*_*hno 1 .net c# user-interface winforms

我正在使用以下控件在 winforms 中加载图像。

https://www.codeproject.com/Articles/43265/ImageListView

(或者)

https://github.com/oozcitak/imagelistview

似乎在 1080P 15 英寸笔记本电脑上存在与此控件相关的一些缩放问题,该问题在 24 英寸 1080P 显示器上无法重现

我最近注意到表单缩放时发生了一件奇怪的事情。直接从 GitHub 下载的主解决方案以及我自己的应用程序中都会发生这种情况。我的电脑显示设置设置为将显示缩放至 125%(右键单击桌面 -> 显示设置 -> 更改文本、应用程序和...的大小)

当我开始调试时,表单会加载 - 正确缩放。但是,一旦我单击树视图中包含图像的文件夹,图像就会加载,并且表单会缩放回 100%。所以整个窗体看起来瞬间缩小了,而 Windows 的其余部分仍然是 125%。

我不确定这是否是 Windows 或 .Net Framework 的错误,或者只是控件的实现方式。或者也许有一个我不知道的属性需要更改?

任何帮助/建议将不胜感激!

更新:

使用 DpiAware 选项后

在此输入图像描述

不使用 DpiAware 选项

在此输入图像描述

TnT*_*nMn 5

我已经能够重现这个问题,但有点奇怪。正如我怀疑的那样,该应用程序未声明为 DPI 感知,将其设置为 DPI 感知可以解决表单大小更改的问题。这可以通过向项目添加清单文件来完成(项目菜单->添加新项目->常规选项卡->选择“应用程序清单文件”。然后将以下内容添加到文件中:

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>
Run Code Online (Sandbox Code Playgroud)

这解决了问题,但我很好奇为什么代码会这样。该进程一开始不支持 DPI,在关闭图像选择对话框后,它以某种方式切换为支持 DPI 的进程。可以使用 SysInternal 的 Process Explorer 应用程序进行观察。我的第一个想法是搜索对SetProcessDpiAwareness 的调用,但没有产生任何结果。深入研究代码发现调用了InitViaWpf中的方法MetadataExtractor.cs。此方法和其他方法利用System.Windows.Media.Imaging命名空间中的类。看来,WPF 库的这种使用方式会导致应用程序变得支持 DPI,就像 WPF 应用程序默认支持 DPI 一样。ImageListView为名为USEWIC的项目声明了一个条件编译符号,用于控制 WPF 类的这种用法。在项目的属性构建配置中删除此符号将阻止它们的使用,并且可以用作替代解决方案,并且可能比将 Winform 应用程序声明为 DPI 感知更好,但我没有时间进一步研究此库。


编辑:通过在尚未标记为 DPI 感知的 Winform 应用程序中创建BitmapFrame实例,可以轻松复制此行为。

using System.Windows.Forms;
using System.IO;
using System.Windows.Media.Imaging;

namespace WindowsFormsApplication1
    {
    public partial class Form1 : Form
        {
        public Form1()
            {
            InitializeComponent();
            }

        private void button1_Click(object sender, EventArgs e)
            {
            using (Stream strm = File.OpenRead("someimage.jpg"))
                {
                BitmapFrame frame = BitmapFrame.Create(strm, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.None);
                }

            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑 2:DPI 感知 winform 缩放过程。

步骤 1:在设计器中,将 AutoScaleMode 属性设置为 Inherit。我知道没有任何意义,但继承是真正的默认设置。

步骤 2:修改表单的构造函数以使用 Dpi 或字体自动缩放。这样做是为了防止设计者记录不正确的 AutoScaleDimensions。

public Form1()
    {
    InitializeComponent();
    // Select either Dpi or font scaling
    this.AutoScaleDimensions = new SizeF(96, 96);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;

    //this.AutoScaleDimensions = new System.Drawing.SizeF(6.0F, 13.0F);
    //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Run Code Online (Sandbox Code Playgroud)

}

编辑 3:要在使用 WPF 库的 DPI 不感知应用程序上维护 DPI 虚拟化(防止自动切换到 DPI 感知),请将该dpiAware部分包含在 app.manifest 文件中,但明确将其设置为 false。

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
    </windowsSettings>
  </application> 
Run Code Online (Sandbox Code Playgroud)