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

WPF主窗口标题栏能否随显示器DPI缩放自动调整?官方示例无效

解决WPF主窗口标题栏随DPI缩放自动调整的问题

核心原因

WPF默认的系统标题栏由操作系统负责渲染,不会自动响应Per-Monitor DPI变化,只有WPF自身绘制的元素会根据DPI缩放,这就是官方PerMonitorDPI示例中标题栏尺寸偏小的原因。

解决方案一:自定义标题栏(推荐)

替换系统标题栏为WPF自定义绘制的组件,确保其随DPI自动缩放,步骤如下:

  1. 禁用系统标题栏
    在窗口XAML中设置相关属性,移除默认标题栏并保留窗口调整功能:
<Window x:Class="YourApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        ResizeMode="CanResize"
        AllowsTransparency="True">
  1. 构建自定义标题栏布局
    在窗口内部添加包含标题文本、控制按钮的标题栏区域,以及主内容区:
<Grid>
    <!-- 自定义标题栏 -->
    <Grid x:Name="TitleBar" Height="32" Background="#FF2D2D30" VerticalAlignment="Top" MouseDown="TitleBar_MouseDown">
        <TextBlock Text="应用标题" Margin="10,0" VerticalAlignment="Center" Foreground="White"/>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="−" Width="46" Height="32" Click="Minimize_Click"/>
            <Button Content="□" Width="46" Height="32" Click="Maximize_Click"/>
            <Button Content="×" Width="46" Height="32" Click="Close_Click"/>
        </StackPanel>
    </Grid>
    <!-- 主内容区域 -->
    <Grid x:Name="MainContent" Margin="0,32,0,0">
        <!-- 你的应用内容 -->
    </Grid>
</Grid>
  1. 添加窗口拖动逻辑
    在标题栏的MouseDown事件中实现窗口拖动:
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        DragMove();
    }
}
  1. 响应DPI变化自动缩放
    在窗口的DpiChanged事件中,基于新的DPI比例调整标题栏尺寸(.NET 5+可省略手动计算,元素会自动跟随DPI缩放):
protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi)
{
    base.OnDpiChanged(oldDpi, newDpi);
    double scale = newDpi.DpiScaleX;
    TitleBar.Height = 32 * scale;
    MainContent.Margin = new Thickness(0, 32 * scale, 0, 0);
    foreach (Button btn in TitleBar.FindVisualChildren<Button>())
    {
        btn.Width = 46 * scale;
        btn.Height = 32 * scale;
    }
}

解决方案二:强制系统标题栏重绘(兼容性一般)

通过Windows API触发系统标题栏重绘,使其适配当前DPI,步骤如下:

  1. 引入Windows API
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

private const int GWL_STYLE = -16;
private const int WS_CAPTION = 0x00C00000;
  1. 在DPI变化时重置窗口样式
protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi)
{
    base.OnDpiChanged(oldDpi, newDpi);
    IntPtr hwnd = new WindowInteropHelper(this).Handle;
    int style = GetWindowLong(hwnd, GWL_STYLE);
    // 先移除标题栏样式再重新添加,触发系统重绘
    SetWindowLong(hwnd, GWL_STYLE, style & ~WS_CAPTION);
    SetWindowLong(hwnd, GWL_STYLE, style | WS_CAPTION);
}

内容的提问来源于stack exchange,提问作者ironsight

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 03:53:20