You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多DPI显示器下WPF Window副屏启动位置及DPI适配问题

解决方案:混合DPI环境下WPF窗口副屏定位错误问题

问题根源

虽然已添加PerMonitorV2清单,但WPF应用启动时UI线程的DPI感知上下文未正确绑定到PerMonitorV2模式,导致窗口位置计算仍使用主显示器的DPI缩放比例,而非目标副屏的参数。

步骤1:导入Win32 API实现线程DPI感知设置

通过P/Invoke调用Windows原生API SetThreadDpiAwarenessContext,将UI线程强制设置为PerMonitorV2感知模式:

using System;
using System.Runtime.InteropServices;

public static class DpiAwarenessHelper
{
    // PerMonitorV2对应的DPI感知上下文值
    private const int DPI_AWARENESS_CONTEXT_PER_MONITOR_V2 = -4;

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);

    /// <summary>
    /// 将当前线程设置为PerMonitorV2 DPI感知模式
    /// </summary>
    public static void EnablePerMonitorV2Awareness()
    {
        SetThreadDpiAwarenessContext(new IntPtr(DPI_AWARENESS_CONTEXT_PER_MONITOR_V2));
    }
}

步骤2:在应用启动最早期调用感知设置

必须在任何WPF控件创建前执行该方法,确保线程DPI感知生效:

方案A:在App.xaml.cs的OnStartup中调用

using System.Windows;
using System.Windows.Media;
using System.Windows.Forms; // 需要添加对System.Windows.Forms的引用

protected override void OnStartup(StartupEventArgs e)
{
    // 先设置DPI感知,再初始化控件
    DpiAwarenessHelper.EnablePerMonitorV2Awareness();
    base.OnStartup(e);

    // 定位窗口到副屏
    var targetWindow = new MainWindow();
    // 获取副屏(根据实际索引调整,AllScreens[0]为主屏,[1]为副屏)
    var secondaryScreen = Screen.AllScreens[1];
    
    // 获取目标窗口的DPI缩放比例(基于副屏)
    var dpiScale = VisualTreeHelper.GetDpi(targetWindow);
    // 将副屏原生像素坐标转换为WPF设备无关像素(DIP)
    targetWindow.Left = secondaryScreen.Bounds.Left / dpiScale.DpiScaleX;
    targetWindow.Top = secondaryScreen.Bounds.Top / dpiScale.DpiScaleY;
    targetWindow.Width = secondaryScreen.Bounds.Width / dpiScale.DpiScaleX;
    targetWindow.Height = secondaryScreen.Bounds.Height / dpiScale.DpiScaleY;
    
    targetWindow.WindowStartupLocation = WindowStartupLocation.Manual;
    targetWindow.Show();
}

方案B:在Main方法中调用(若使用自定义入口)

using System;
using System.Windows;

[STAThread]
static void Main()
{
    DpiAwarenessHelper.EnablePerMonitorV2Awareness();
    var app = new App();
    app.Run();
}

步骤3:验证清单文件配置

确保项目的应用清单中PerMonitorV2配置正确,避免冲突:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
  </windowsSettings>
</application>

关键注意事项

  • 必须在UI线程创建任何WPF控件前调用EnablePerMonitorV2Awareness,否则设置无效。
  • 若项目未引用System.Windows.Forms,需在NuGet或项目引用中添加该程序集(用于获取副屏信息)。
  • 转换坐标时,务必使用目标窗口所在显示器的DPI缩放比例,而非主显示器参数。

内容的提问来源于stack exchange,提问作者Jan Van Overbeke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:15:30