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

如何创建随窗口高度缩放且不受系统DPI影响的WPF工业监控应用?

WPF工业监控应用多分辨率与DPI适配方案

核心需求梳理

针对1024x768基准分辨率设计UI,实现:

  • 全屏运行,适配1024x768/1920x1080/1920x1200等分辨率
  • 所有元素随窗口高度等比例缩放
  • 部分区域宽度自适应窗口宽度
  • 忽略系统DPI缩放(100%/125%/150%)
  • 展示固定信息量,暂不做分宽高比的多布局

一、禁用系统DPI缩放

要忽略系统DPI设置,需让WPF直接使用设备像素而非设备独立像素(DIP),有两种可靠实现方式:

1. 应用清单配置

在项目的app.manifest中添加以下配置,强制应用不参与系统DPI缩放:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
  </windowsSettings>
</application>

2. 代码级强制

在App.xaml.cs的OnStartup方法中重置DPI转换矩阵,直接映射设备像素:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var mainWindow = new MainWindow();
    var source = PresentationSource.FromVisual(mainWindow);
    if (source != null)
    {
        source.CompositionTarget.TransformToDevice = Matrix.Identity;
        source.CompositionTarget.TransformFromDevice = Matrix.Identity;
    }
    mainWindow.Show();
}

二、布局实现方案

方案1:自定义缩放容器(推荐)

自定义ScaledPanel继承自Panel,自动按窗口高度比例缩放子元素,同时支持标记元素宽度自适应:

容器代码

using System.Windows;
using System.Windows.Controls;

public class ScaledPanel : Panel
{
    // 基准高度(1024x768中的768)
    public static readonly DependencyProperty BaseHeightProperty =
        DependencyProperty.Register("BaseHeight", typeof(double), typeof(ScaledPanel), 
            new PropertyMetadata(768.0, (s, e) => ((ScaledPanel)s).InvalidateArrange()));

    public double BaseHeight
    {
        get => (double)GetValue(BaseHeightProperty);
        set => SetValue(BaseHeightProperty, value);
    }

    // 标记元素是否宽度自适应
    public static readonly DependencyProperty IsWidthAdaptiveProperty =
        DependencyProperty.RegisterAttached("IsWidthAdaptive", typeof(bool), typeof(ScaledPanel), 
            new PropertyMetadata(false));

    public static void SetIsWidthAdaptive(UIElement element, bool value)
        => element.SetValue(IsWidthAdaptiveProperty, value);

    public static bool GetIsWidthAdaptive(UIElement element)
        => (bool)element.GetValue(IsWidthAdaptiveProperty);

    protected override Size MeasureOverride(Size availableSize)
    {
        var scale = availableSize.Height / BaseHeight;
        var scaledSize = new Size(availableSize.Width / scale, availableSize.Height / scale);

        foreach (UIElement child in Children)
        {
            if (GetIsWidthAdaptive(child))
                child.Measure(new Size(double.PositiveInfinity, scaledSize.Height));
            else
                child.Measure(scaledSize);
        }
        return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        var scale = finalSize.Height / BaseHeight;

        foreach (UIElement child in Children)
        {
            if (GetIsWidthAdaptive(child))
            {
                var scaledHeight = child.DesiredSize.Height * scale;
                child.Arrange(new Rect(0, 0, finalSize.Width, scaledHeight));
            }
            else
            {
                var scaledWidth = child.DesiredSize.Width * scale;
                var scaledHeight = child.DesiredSize.Height * scale;
                child.Arrange(new Rect(0, 0, scaledWidth, scaledHeight));
            }
        }
        return finalSize;
    }
}

XAML使用示例

<Window x:Class="IndustrialMonitor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:IndustrialMonitor"
        WindowState="Maximized" WindowStyle="None">
    <local:ScaledPanel BaseHeight="768">
        <!-- 固定缩放元素:按1024x768基准等比例缩放 -->
        <Grid Width="1024">
            <TextBlock Text="工业监控系统" FontSize="24" Margin="10"/>
            <!-- 其他固定布局控件(如仪表盘、状态灯) -->
        </Grid>

        <!-- 宽度自适应元素:占满窗口宽度,高度按比例缩放 -->
        <Grid local:ScaledPanel.IsWidthAdaptive="True" Margin="10,0">
            <TextBlock Text="实时生产数据" HorizontalAlignment="Center"/>
            <!-- 自适应宽度的表格、趋势图等 -->
        </Grid>
    </local:ScaledPanel>
</Window>

方案2:绑定缩放比例(灵活度高)

如果需要更精细的控制,可在窗口中定义高度缩放比例,手动绑定到元素的高度、字体大小、边距等属性:

窗口代码

using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private double _heightScale;
    public double HeightScale
    {
        get => _heightScale;
        set
        {
            _heightScale = value;
            OnPropertyChanged();
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        HeightScale = ActualHeight / 768.0;
    }

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        => HeightScale = e.NewSize.Height / 768.0;

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}

// 缩放转换器
public class ScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is double scale && double.TryParse(parameter.ToString(), out double baseValue))
            return scale * baseValue;
        return baseValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        => throw new NotImplementedException();
}

XAML使用示例

<Window x:Class="IndustrialMonitor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:IndustrialMonitor"
        WindowState="Maximized" WindowStyle="None"
        SizeChanged="Window_SizeChanged">
    <Window.Resources>
        <local:ScaleConverter x:Key="ScaleConverter"/>
    </Window.Resources>
    <Grid>
        <!-- 固定缩放区域 -->
        <Grid x:Name="FixedGrid" Width="1024" HorizontalAlignment="Left">
            <TextBlock Text="监控标题" 
                       FontSize="{Binding HeightScale, Converter={StaticResource ScaleConverter}, ConverterParameter=24}"
                       Margin="{Binding HeightScale, Converter={StaticResource ScaleConverter}, ConverterParameter=10}"/>
        </Grid>

        <!-- 宽度自适应区域 -->
        <Grid Margin="{Binding ElementName=FixedGrid, Path=Width}" HorizontalAlignment="Stretch">
            <TextBlock Text="自适应数据区" FontSize="{Binding HeightScale, Converter={StaticResource ScaleConverter}, ConverterParameter=18}"/>
        </Grid>
    </Grid>
</Window>

三、关键注意事项

  • 禁用DPI缩放后,所有WPF控件的尺寸直接映射屏幕物理像素,无需额外处理系统DPI设置
  • 两种方案均保证元素高度按窗口高度比例缩放,固定信息量的展示不会因分辨率变化丢失内容
  • 若后续需要支持宽高比适配,可在ScaledPanel中添加宽高比判断逻辑,切换不同基准布局

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:01:05