当 DPI 高于 96 并调用特定方法时,表单混乱

Form messed up when DPI above 96 and specific method is called

我有一个重载方法,它获取上传图像中的字节,这似乎导致我的整个应用程序调整大小。这似乎仅在显示缩放比例不是 100% 时才会发生。

奇怪的是,应用程序在进入重载方法时调整大小,但在方法中的任何实际代码之前 运行。更奇怪的是,如果我将 DPI 比例设置为 100%,执行调整表单大小的常规操作,然后将显示比例切换回 125%,则不会发生调整大小。

这是方法:

public static byte[] GetMultiPageImageBytes(byte[] imageBytes, double? rotationAngle, string subject)
{
    using (MemoryStream inStream = new MemoryStream(imageBytes))
    {
        return GetMultiPageImageBytes(inStream, rotationAngle, subject);
    }
}

和重载方法(发生调整大小的地方):

public static byte[] GetMultiPageImageBytes(Stream inStream, double? rotationAngle, string subject)
{ /************************ APP RESIZES ON THIS LINE ************************/
    BitmapDecoder decoder = new TiffBitmapDecoder(inStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    TiffBitmapEncoder encoder = new TiffBitmapEncoder();

    foreach (BitmapFrame frame in decoder.Frames)
    {
        BitmapMetadata metadata = null;
        if (subject != null)
        {
            metadata = new BitmapMetadata("tiff");
            metadata.Subject = subject;
        }

        TransformedBitmap rotatedImage = null;
        if (rotationAngle != null)
        {
            System.Windows.Media.RotateTransform transform = new System.Windows.Media.RotateTransform(rotationAngle.Value);
            rotatedImage = new TransformedBitmap(frame, transform);
        }

        BitmapSource sourceImage = rotatedImage != null ? (BitmapSource)rotatedImage : (BitmapSource)frame;
        BitmapFrame newFrame = BitmapFrame.Create(sourceImage, frame.Thumbnail, metadata, frame.ColorContexts);

        encoder.Frames.Add(newFrame);
    }

    using (MemoryStream outStream = new MemoryStream())
    {
        encoder.Save(outStream);
        return outStream.ToArray();
    }
}

我试过 SetProcessDPIAware() 解决了这个问题,但是弄乱了其他几十个表单和组件的布局。该应用程序太大,无法在此时优化 DPI 感知,因为我需要重新格式化数十个组件。

我还尝试删除调用重载方法的原始方法中的 using 语句,然后手动处理流,但这也不起作用:

// 没用

public static byte[] GetMultiPageImageBytes(byte[] imageBytes, double? rotationAngle, string subject)
{
    MemoryStream inStream = new MemoryStream(imageBytes);
    byte[] bytes;
    bytes = GetMultiPageImageBytes(inStream, rotationAngle, subject);
    inStream.Dispose();
    inStream.Close();
    return bytes;
}

关于可能导致这种情况的原因有什么想法吗?如有任何帮助,我们将不胜感激!

部分答案 - 这可能发生在某些 class 的静态构造函数中,该构造函数首先在此方法中使用。静态构造函数保证在 class 的第一次实例化或调用其静态方法之一之前的某个时间被调用。在这样的方法开始时看到这种情况是很典型的。所以这就解释了奇怪的时机。恐怕我对 WinForm 或 WPF 的了解还不足以解释其余部分,所以我不会推测。


具体来说,我建议在您的第二个 GetMultiPageImageBytes 方法开始时调用以下任何 classes 的静态构造函数,如果它们没有被调用的话已经:

  • TiffBitmap解码器
  • TiffBitmapEncoder
  • 位图元数据
  • 旋转变换
  • TransformedBitmap
  • 位图帧
  • 他们的任何基础 classes

.NET 规范不会说 确切地 何时调用静态构造函数,只是说它 在某个时候被调用在 class 的第一次实例化或调用其静态方法之一之前。通常,您将看到的行为是它将在 going 执行其中一项操作的方法开始时被调用。这就是为什么我说它是一种看似合理的机制,可以在您的方法的第一行发生奇怪的事情,即使它还没有做任何事情。很可能是这样的静态构造函数或它导致 运行 的其他代码导致了您的奇怪行为。

确实,这个答案表明 loading any WPF classses causes the process to be set to DPI-aware。基于此,您的问题可能是 WPF classes 根本没有设计为在 non-WPF 应用程序中独立使用。根据您问题标题中的“WinForm”,我假设您应用程序其余部分的 none 是 WPF。

根据@Jimi 的建议禁用 DPI 感知对我有用。我最终使用了这个答案中的代码: 来自@Marko