我有一个
System.Window.Forms.Form
,我可以在其中处理每次按钮点击。当我收到第一个事件时,我创建一个新的 WPF System.Windows.Window
对象。
class WPF_Window : Window
{
}
public partial class Form1 : Form
{
WPF_Window wnd = null;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (wnd == null)
{
wnd = new WPF_Window();
}
}
}
在我的计算机上,此代码按预期工作,但如果我在另一台计算机(均为 Windows 10)上运行它,当我单击 Windows 窗体窗口时,它会更改其大小(减小其尺寸)。
这怎么可能?我怎样才能避免这种行为?
您发现 WPF 调用 SetProcessDPIAware()。 它发生在PresentationCore 的模块初始值设定项内。 这在形式上是非法的,必须始终在应用程序创建任何窗口或加载可能缓存 DPI 值的 DLL 之前调用它。 或者换句话说,有很多方法可能会出错,但你到目前为止只发现了它的温和版本。 在纯 WPF 应用程序中通常不会出现问题,因为在创建任何窗口之前始终需要加载PresentationCore。
他们确实留下了后门来禁用这种行为。 复制/粘贴此代码,最好将其粘贴到 EXE 项目的 AssemblyInfo.cs 源文件中:
[assembly: System.Windows.Media.DisableDpiAwareness]
但这当然不是一个真正的解决方案,DPI 虚拟化现在始终为您的所有窗口启用。 通过在清单中声明您的应用程序支持 dpi 来取得进展,这样PresentationCore 就不会搞砸了。 但不可避免的副作用是,您现在会发现需要修复 Winforms UI。 当您更改 Form.AutoScaleMode 属性或执行一些不明智的操作(例如对窗口大小进行硬编码)时,它只会变得更小。 该属性是 Q&D 修复。
这些是您可以使用的一些方法。设置窗口的宽度和高度:
public static Graphics graphics = Graphics.FromHwnd(IntPtr.Zero);
public static double GetDIPIndependent(double value, double DPI)
{
value = value * (graphics.DpiX / DPI);
return value;
}
public static double GetDIPDependent(double value, double DPI)
{
value = value * (DPI / graphics.DpiX);
return value;
}
public static double GetDIPIndependent(double value)
{
value = value * (graphics.DpiX / 96.0);
return value;
}
public static double GetDIPDependent(double value)
{
value = value * (96.0 / graphics.DpiX);
return value;
}
this.Width = GetDIPIndependent(this.Width)
this.Height = GetDIPIndependent(this.Height)
this.Width = GetDIPDependent(this.Width)
this.Height = GetDIPDependent(this.Height)
它对我有用...
当我使用 Windows 窗体中托管的 WPF 控件时,我遇到了同样的问题。当分辨率未缩放(无缩放,100%)时,所有行为均按预期进行。当在 4K 或 8K 屏幕上启用缩放(缩放,200%)时,WPF 控件会将整个应用程序缩放 100% - 因此它变得非常小,尤其是在 8K 屏幕上。
Hans Passant 的解决方案非常完美。不幸的是,AssemblyInfo.cs 已被弃用。虽然它仍然有效;考虑到所有相关情况,我建议这样做。
AssemblyInfo.cs - add [assembly: System.Windows.Media.DisableDpiAwareness]
如果不能使用 AssemblyInfo.cs,我已在启动对象 (main.cs) 中使用以下代码成功实现了相同的结果。
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace App
{
static class Program
{
[DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
[DllImport("shcore.dll")]
private static extern int SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);
private enum PROCESS_DPI_AWARENESS
{
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
}
[STAThread]
static void Main()
{
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_DPI_Unaware);
...
...
...