WPF 高 DPI 下的 SizeToContent

WPF 高 DPI 下的 SizeToContent

这两天解决了一个 WPF 界面方面的问题:某个窗体运行在 1366*768 分辨率的屏幕上,并且窗口设置了 SizeToContent="WidthAndHeight" 属性,即窗体的尺寸将随内容而变化。当系统的 DPI 为默认的 96 时,一切呈现正常;但是当设置系统的 DPI 为 144 时,界面右侧被截断。既然窗体的尺寸随内容而变化,DPI 的修改怎会导致显示不全呢?究其原因,此问题是由 DPI 和 SizeToContent 共同造成的。

WPF 尺寸单位与 DPI 的关系

为了弄清楚显示不全的原因,我们需要先明确计算机系统和 WPF 程序中的一些尺寸概念:

  • 屏幕分辨率:即我们通常所说的屏幕尺寸,比如 1366*7681920*1080,其单位为:像素
  • 系统 DPI:每英寸的点数(像素个数),通常情况下系统的默认 DPI 为: 96
  • WPF 尺寸单位:设备无关单位,其值为:[1/96] 英寸

通过如上定义可以推算,当系统的 DPI 为 96 时,则有 WPF 尺寸单位 = [1/96] 英寸 * 96 像素/英寸 = 1 像素 。同理,如果系统的 DPI 设置为 144 ,则有 WPF 尺寸单位 = 1.5 像素

SizeToContent 将限定 Window 的最大尺寸

在 WPF 程序中,当设置了 Window 的 SizeToContent="WidthAndHeight" 属性时,窗体的大小会随内容的尺寸而变化。但是,此时窗体的最大尺寸也将受限于屏幕的尺寸,例如在分辨率为 1366*768(单位:像素) 的屏幕上时,该窗体的最大宽度将为 1380 像素 左右(之所以比 1366 大一点,是因为系统设置了窗体边框)。

注意,此处 1380 的单位是 “像素”,在 144 DPI 下换算为 “WPF 尺寸单位”,则为 920。即此窗体的最大尺寸将为 920 个 WPF尺寸单位。

问题原因

先来看一下界面的相关代码:

<Window x:Class="Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" Title="MainWindow" WindowStartupLocation="CenterScreen"
        SizeToContent="WidthAndHeight">
    <Grid Width="1200" Background="LightCoral" Height="300">
        <!--内部代码省略-->
    </Grid>
</Window>

结合前面介绍的 WPF 尺寸单位SizeToContent 对窗体最大尺寸的影响,我们可以轻松的分析出显示不全的原因:在 1366*768 分辨率下,SizeToContent="WidthAndHeight" 将窗体的最大尺寸限定为了 1380 像素,在 144 DPI 下换算为 WPF 尺寸单位920 ,而窗口的内容尺寸被设定为了 1200(WPF 尺寸单位),超出了窗体的最大尺寸,所以内容被截断。而在 96 DPI 下,1380像素 换算为 WPF 尺寸单位为 1380(WPF 尺寸单位),内容尺寸在窗体的最大尺寸范围内,窗口的大小将随内容尺寸而定。

解决方案

当窗体的最大尺寸小于内容的尺寸时,我们可以使用 Viewbox 来实现内容的整体缩小。即在界面的根部放置一个 Viewbox 控件,默认情况下 Stretch="None",即不缩放内容。当窗口的尺寸小于内容的尺寸时,说明窗体的大小受限于最大尺寸,SizeToContent 不生效了,此时启用 Viewbox 的缩放功能。

<Viewbox x:Name="RootViewbox" Stretch="None">
    <Grid x:Name="RootGrid" Width="1200" Background="LightCoral" Height="300">
        <!--内部代码省略-->
    </Grid>
</Viewbox>
protected override void OnContentRendered(EventArgs e)
{
    base.OnContentRendered(e);

    // 窗体尺寸和内容尺寸不一致,说明已经受限于最大尺寸,此时缩放内容
    if (ActualWidth < RootGrid.ActualWidth)
    {
        RootViewbox.Stretch = Stretch.Uniform;
    }
}

在 WPF 应用程序的开发中,一定要考虑 DPI 对界面呈现的影响,不然会出现显示不全或尺寸不协调等问题。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ironyho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值