当 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
我有一个重载方法,它获取上传图像中的字节,这似乎导致我的整个应用程序调整大小。这似乎仅在显示缩放比例不是 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 感知对我有用。我最终使用了这个答案中的代码: