WPF系统DPI缩放场景下窗口尺寸异常问题求助
解决WPF窗口在高DPI缩放系统下固定尺寸不受影响的问题
可行解决方案
1. 配置正确的DPI感知清单
在app.manifest中替换原有DPI相关配置,启用每显示器DPI感知v2,这是实现固定物理尺寸的基础:
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <!-- 保留其他原有清单内容 --> <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> </assembly>
2. 强制窗口固定物理像素尺寸+修正内部元素缩放
在窗口代码中,通过获取当前显示器DPI计算转换比例,手动锁定窗口物理尺寸,并覆盖WPF的自动缩放逻辑:
using System; using System.Windows; using System.Windows.Interop; using System.Windows.Media; public partial class MainWindow : Window { private const int TargetPhysicalWidth = 512; private const int TargetPhysicalHeight = 512; public MainWindow() { InitializeComponent(); SourceInitialized += MainWindow_SourceInitialized; } private void MainWindow_SourceInitialized(object sender, EventArgs e) { var hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); if (hwndSource == null) return; // 获取当前显示器的DPI缩放比例 var dpiScaleX = hwndSource.CompositionTarget.TransformToDevice.M11; var dpiScaleY = hwndSource.CompositionTarget.TransformToDevice.M22; // 将目标物理像素转换为WPF设备无关单位,设置窗口尺寸 Width = TargetPhysicalWidth / dpiScaleX; Height = TargetPhysicalHeight / dpiScaleY; // 强制内部元素不随DPI缩放,保持1:1物理像素对应 hwndSource.CompositionTarget.TransformToDevice = Matrix.Identity; hwndSource.CompositionTarget.TransformFromDevice = Matrix.Identity; // 监听DPI变化事件,窗口跨显示器时保持尺寸不变 hwndSource.AddHook(HwndSourceHook); } private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { const int WM_DPICHANGED = 0x02E0; if (msg == WM_DPICHANGED) { // 解析新显示器的DPI值 var newDpiX = (int)(wParam.ToInt64() & 0xFFFF); var newDpiY = (int)(wParam.ToInt64() >> 16); var dpiScaleX = newDpiX / 96.0; var dpiScaleY = newDpiY / 96.0; // 重新计算窗口尺寸,维持物理像素不变 Width = TargetPhysicalWidth / dpiScaleX; Height = TargetPhysicalHeight / dpiScaleY; // 保持内部元素缩放比例为1 var hwndSource = HwndSource.FromHwnd(hwnd); hwndSource.CompositionTarget.TransformToDevice = Matrix.Identity; hwndSource.CompositionTarget.TransformFromDevice = Matrix.Identity; handled = true; } return IntPtr.Zero; } }
3. 清理冲突配置
- 移除
AssemblyInfo.cs中的[assembly: System.Windows.Media.DisableDpiAwareness]配置,避免与PerMonitorV2感知冲突 - 删除
app.config中Switch.System.Windows.DoNotScaleForDpiChanges的设置,保持默认即可
原理说明
- 启用PerMonitorV2后,应用可直接感知当前显示器DPI,避免系统强制缩放整个窗口
- 通过将
CompositionTarget的转换矩阵设为单位矩阵,强制WPF内部元素布局与物理像素1:1对应,解决元素被缩放的问题 - 监听
WM_DPICHANGED事件,在窗口切换到不同DPI显示器时,重新计算窗口尺寸,始终维持目标物理像素大小
内容的提问来源于stack exchange,提问作者Cyclone
相关产品推荐
相关产品推荐

