当我创建 WPF 窗口时,Windows 窗体窗口会更改其大小

问题描述 投票:0回答:4

我有一个

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 窗体窗口时,它会更改其大小(减小其尺寸)。

这怎么可能?我怎样才能避免这种行为?

c# wpf winforms resize interop
4个回答
11
投票

您发现 WPF 调用 SetProcessDPIAware()。 它发生在PresentationCore 的模块初始值设定项内。 这在形式上是非法的,必须始终在应用程序创建任何窗口或加载可能缓存 DPI 值的 DLL 之前调用它。 或者换句话说,有很多方法可能会出错,但你到目前为止只发现了它的温和版本。 在纯 WPF 应用程序中通常不会出现问题,因为在创建任何窗口之前始终需要加载PresentationCore。

他们确实留下了后门来禁用这种行为。 复制/粘贴此代码,最好将其粘贴到 EXE 项目的 AssemblyInfo.cs 源文件中:

   [assembly: System.Windows.Media.DisableDpiAwareness]

但这当然不是一个真正的解决方案,DPI 虚拟化现在始终为您的所有窗口启用。 通过在清单中声明您的应用程序支持 dpi 来取得进展,这样PresentationCore 就不会搞砸了。 但不可避免的副作用是,您现在会发现需要修复 Winforms UI。 当您更改 Form.AutoScaleMode 属性或执行一些不明智的操作(例如对窗口大小进行硬编码)时,它只会变得更小。 该属性是 Q&D 修复。


3
投票

正如其他回复中所述,这是因为DPI意识。对于那些使用 VB.NET 的人来说,快速修复将其关闭:

打开app.manifest

Enter image description here

然后取消这部分的注释,并将DPI感知设置为false

Enter image description here

请注意,这可能会导致应用程序的字体在更高 DPI 的设备上看起来更加模糊。


2
投票

这些是您可以使用的一些方法。设置窗口的宽度和高度:

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;
}

示例:

如果 DPI 独立

this.Width = GetDIPIndependent(this.Width)
this.Height = GetDIPIndependent(this.Height)

如果依赖于 DPI

this.Width = GetDIPDependent(this.Width)
this.Height = GetDIPDependent(this.Height)

它对我有用...


0
投票

当我使用 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);
        
            ...
            ...
            ...
© www.soinside.com 2019 - 2024. All rights reserved.