在设置桌面不同分辨率以及较大DPI下,窗口如何显示的问题。

方案一 设置窗口最大值和最小值显示

通过对比当前屏幕的可显示区域,将窗口高宽最大值和最小值,设置为窗口的实际高宽(此例中仅设置高度)

界面设置

  1. 设置窗口内容自适应SizeToContent="WidthAndHeight"
  2. 添加ViewBox -- 设置默认不拉伸Stretch="None",当DPI超大时如超过1920*1080p的175%(即win10默认不支持的比例显示),开启ViewBox缩放
  3. 顶层布局容器RootGrid添加高宽最大值和最小值。
 <Window x:Class="WindowHeightChangedForDpi.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"
xmlns:local="clr-namespace:WindowHeightChangedForDpi"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen">
<Viewbox x:Name="RootViewbox" Stretch="None">
<Grid x:Name="RootGrid" Width="" MaxHeight="" MinHeight="" ClipToBounds="True"> </Grid>
</Viewbox>
</Window>

后台设置 - 窗口大小自适应设置

  1. 添加对Loaded事件的监听,并在之后注销。窗口只需要首次初始其高度即可。
  2. 获取屏幕的高度和任务栏的高度 -- 具体可以参考C# 获取当前屏幕的宽高和位置
  3. 比较当前可显示高度(屏幕高度-任务栏高度)与窗口的最大/最小高度,然后设置当前窗口的实际高度。
  4. 如果可显示高度比最小值还小,则开启ViewBox内容缩放。ViewBox的高度为当前可显示高度。
  5. 如果当前窗口有阴影,可设置阴影高度大小。保证窗口在可显示区域内正常显示。
     public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += InitWindowActualHeight_OnLoaded;
} #region 设置窗口对屏幕高度的自适应 private void InitWindowActualHeight_OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= InitWindowActualHeight_OnLoaded;
InitWindowActualHeight();
} private const double WindowShadowHeight = ; private void InitWindowActualHeight()
{
//获取窗体所在屏幕的高度
var visibleAreaHeight = GetScreenHeight(); //可显示高度 > 窗口最大高度
if (visibleAreaHeight > RootGrid.MaxHeight + WindowShadowHeight)
{
//设置高度等于最大高度
RootGrid.Height = RootGrid.MaxHeight;
}
//可显示高度 < 窗口最小高度
else if (visibleAreaHeight < RootGrid.MinHeight + WindowShadowHeight)
{
//设置Viewbox高度=可视高度-阴影高度(此处通过绽放显示窗口,所以不能通过设置窗口或者设置内容的高度来实现)
RootViewbox.Height = visibleAreaHeight - WindowShadowHeight;
//等比例缩小
RootViewbox.Stretch = Stretch.Uniform;
}
else
{
//设置高度等于最小高度
RootGrid.Height = RootGrid.MinHeight;
}
}
const double DpiPercent = ;
private double GetScreenHeight()
{
var intPtr = new WindowInteropHelper(this).Handle;//获取当前窗口的句柄
var screen = Screen.FromHandle(intPtr);//获取当前屏幕 double height = ;
using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
{
double dpiXRatio = currentGraphics.DpiX / DpiPercent;
double dpiYRatio = currentGraphics.DpiY / DpiPercent;
height = screen.WorkingArea.Height / dpiYRatio;
//var width = screen.WorkingArea.Width / dpiXRatio;
//var left = screen.WorkingArea.Left / dpiXRatio;
//var top = screen.WorkingArea.Top / dpiYRatio;
}
return height;
}
#endregion
}

注:获取的屏幕高度为屏幕像素,需要转换为WPF单位。

以上只是设置了高度的最大值最值,如果需要,可以对高度设置多个梯度,对应不同分辨率下的显示。

下载Demo

方案二 设置窗口为屏幕的百分比(如60%)显示

窗口设置为屏幕的百分比大小(如60%高宽)显示,在这基础上添加限制(最大值、最小值)。

如此,对多种分辨率、DPI比例,我们开发时就不需要考虑其它因素,简单明了且所有窗口大小能统一。

比如主窗口A设置为屏幕可显示区域的60%大小,二级子窗口设置为可显示区域的40%大小,三级子窗口设置为可显示区域的30%大小。

实现方案与案例

通过添加附加属性,设置当前窗口宽为可显示区域的80%大小,高为可显示区域高的75%大小。

 <Window x:Class="WindowSizeToScreenRatioDisplay.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"
xmlns:local="clr-namespace:WindowSizeToScreenRatioDisplay"
mc:Ignorable="d"
Title="MainWindow"
local:WindowAdaptation.WidthByScreenRatio="0.8" MaxWidth="1200" MinWidth="800"
local:WindowAdaptation.HeightByScreenRatio="0.75" MaxHeight="800" MinHeight="520">
<Grid Background="CornflowerBlue"> </Grid>
</Window>

添加附加属性 WidthByScreenRatio、HeightByScreenRatio。

控制窗口大小:

  1. 默认设置为当前屏幕工作区域的显示比例大小
  2. 如果超过窗口最大高度/宽高,则显示为窗口最大高度/宽高
  3. 如果小于窗口最小高度/宽高,则显示为当前可显示区域的最大高度/宽高
     /// <summary>
/// 为窗口<see cref="Window"/>添加附加属性的辅助类
/// </summary>
public class WindowAdaptation
{
#region 窗口宽度比例
/// <summary>
/// 窗口宽度比例 单位:小数(0 - 1.0]
/// <para>窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例</para>
/// </summary>
public static readonly DependencyProperty WidthByScreenRatioProperty = DependencyProperty.RegisterAttached(
"WidthByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnWidthByScreenRatioPropertyChanged)); private static void OnWidthByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Window window && e.NewValue is double widthByScreenRatio)
{
if (widthByScreenRatio <= || widthByScreenRatio > )
{
throw new ArgumentException($"屏幕比例不支持{widthByScreenRatio}");
} var screenDisplayArea = GetScreenSize(window);
var screenRatioWidth = screenDisplayArea.Width * widthByScreenRatio; if (!double.IsNaN(window.MaxWidth) && screenRatioWidth > window.MaxWidth)
{
window.Width = window.MaxWidth;
}
else if (!double.IsNaN(window.MinWidth) && screenRatioWidth < window.MinWidth)
{
window.Width = screenDisplayArea.Width;
}
else
{
window.Width = screenRatioWidth;
}
}
} public static void SetWidthByScreenRatio(DependencyObject element, double value)
{
element.SetValue(WidthByScreenRatioProperty, value);
} public static double GetWidthByScreenRatio(DependencyObject element)
{
return (double)element.GetValue(WidthByScreenRatioProperty);
}
#endregion #region 窗口高度比例
/// <summary>
/// 窗口宽度比例 单位:小数(0 - 1.0]
/// <para>窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例</para>
/// </summary>
public static readonly DependencyProperty HeightByScreenRatioProperty = DependencyProperty.RegisterAttached(
"HeightByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnHeightByScreenRatioPropertyChanged)); private static void OnHeightByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Window window && e.NewValue is double heightByScreenRatio)
{
if (heightByScreenRatio <= || heightByScreenRatio > )
{
throw new ArgumentException($"屏幕比例不支持{heightByScreenRatio}");
} var screenDisplayArea = GetScreenSize(window);
var screenRatioHeight = screenDisplayArea.Height * heightByScreenRatio; if (!double.IsNaN(window.MaxHeight) && screenRatioHeight > window.MaxHeight)
{
window.Height = window.MaxHeight;
}
else if (!double.IsNaN(window.MinHeight) && screenRatioHeight < window.MinHeight)
{
window.Height = screenDisplayArea.Height;
}
else
{
window.Height = screenRatioHeight;
}
}
} public static void SetHeightByScreenRatio(DependencyObject element, double value)
{
element.SetValue(HeightByScreenRatioProperty, value);
} public static double GetHeightByScreenRatio(DependencyObject element)
{
return (double)element.GetValue(HeightByScreenRatioProperty);
}
#endregion const int DpiPercent = ;
private static dynamic GetScreenSize(Window window)
{
var intPtr = new WindowInteropHelper(window).Handle;//获取当前窗口的句柄
var screen = Screen.FromHandle(intPtr);//获取当前屏幕
using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
{
//分别获取当前屏幕X/Y方向的DPI
double dpiXRatio = currentGraphics.DpiX / DpiPercent;
double dpiYRatio = currentGraphics.DpiY / DpiPercent; var width = screen.WorkingArea.Width / dpiXRatio;
var height = screen.WorkingArea.Height / dpiYRatio; return new { Width = width, Height = height };
}
}
}

下载 Demo

下图为1920*1080p的175%DPI显示:

下图为1366*768的125%DPI下显示:

WPF 窗口大小自适应的更多相关文章

  1. 解决extjs grid 不随窗口大小自适应的问题

    解决extjs grid 不随窗口大小自适应的问题 August 30, 2010 zhai Javascript 8,403 viewsGo to comment 最近遇到的问题,在使用grid的时 ...

  2. [WPF]建立自适应窗口大小布局的WinForm窗口

    编写WinForm程序时,都会碰到一个问题.就是WinForm窗口在不同分辨率下的大小问题.举例说明,你编写的WinForm窗口在1024×768下是合适.匀称的.不过,如果用户的计算机的分辨率为14 ...

  3. WPF 窗口自适应

    窗口自适应就是说,当主窗口缩放的时候,内部的控件位置自动的调整,而不是隐藏掉.这主要依赖于Grid布局. 1.比如这个groupbox 本身是在一个Grid的Row中的.缩放之后,左边的button不 ...

  4. 转载【Ubuntu】Ubuntu14.04虚拟机调整窗口大小自适应VMware14窗口

    Ubuntu屏幕居中一小块,很不好看 查看-–> 自动调整大小—>自动适应客户机/自动适应窗口 切一下就可以把Ubuntu图的界面大小调的和VMware窗口自适应了 效果:   转载 自h ...

  5. 利用$(window).resize()实现窗口大小自适应宽度问题

    © 版权声明:本文为博主原创文章,转载请注明出处 问题描述:利用iframe做页面引入,用$(window).resize()作自适应:结果窗口变小时,利用$(window).width()获取到的宽 ...

  6. WPF窗体自适应分辨率

    使用WPF创建一个窗体(Window)时,如果设置了固定的高度(Height)和宽度(Width),一旦用户的电脑分辨率过低,就会使得窗体及其中的内容无法完整地显示出来.要解决这个这个问题,有以下几个 ...

  7. PB笔记之数据窗口大小自适应的方式

    1.在OPEN 事件中设置数据窗口大小属性 tab_1.tabpage_6.dw_6.x=0tab_1.tabpage_6.dw_6.y=0tab_1.tabpage_6.dw_6.width=thi ...

  8. Ubuntu 16.04虚拟机调整窗口大小自适应Windows 7

    Windows 7上Ubuntu 16.04虚拟机安装成功后,默认的虚拟机窗口比较小,需要适当调整,才能把虚拟机的屏幕放大, 适合使用,以下介绍调整方法. 安装VMware Tools  启动虚拟机, ...

  9. 完整版ajax+百度echarts实现统计图表demo并随着窗口大小改变而自适应

    1.前言 百度Echarts会常用到我们的项目中做统计,api很详细,demo也非常之多,我们常用的是应有尽有了,做一些小项目的时候,百度echarts的demo已足够用了.今天呢.主要是跟小白讲一下 ...

随机推荐

  1. python学习相关知识点

    1.ndarray中,添加行或列:https://blog.csdn.net/lishuandao/article/details/52444288 2.numpy中ndarray数组拼接方法介绍:h ...

  2. [Lyft Level 5 Challenge 2018 - Elimination Round][Codeforces 1033D. Divisors]

    题目链接:1033D - Divisors 题目大意:给定\(n\)个数\(a_i\),每个数的约数个数为3到5个,求\(\prod_{i=1}^{n}a_i\)的约数个数.其中\(1 \leq n ...

  3. Java内存模型锦集

    [内存操作与内存屏障] 内存模型操作: lock(锁定) : 作用与主内存的变量, 它把一个变量标识为一条线程独占的状态 unlock(解锁) : 作用于主内存变量, 它把一个处于锁定状态的变量释放出 ...

  4. JavaSSM框架面试

    一.Spring面试题 1.Spring 在ssm中起什么作用? Spring:轻量级框架 作用:Bean工厂,用来管理Bean的生命周期和框架集成. 两大核心: 1.IOC/DI(控制反转/依赖注入 ...

  5. Java二叉树实现及递归与非递归遍历实现

    树的遍历分两种:1.深度优先遍历 1.1 递归算法实现 2.2 非递归算法实现(使用栈存储)2.广度优先遍历(使用队列存储) import java.util.*; /** * 类功能描述: 二叉树遍 ...

  6. [Swift]LeetCode188. 买卖股票的最佳时机 IV | Best Time to Buy and Sell Stock IV

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  7. Truncated incorrect DOUBLE value: 'd'的解决方法(jdbc)

    今天写jdbc中dao的增删改查时遇到了一个问题,花费了好长时间,不过还好,有我峰哥出头,问题解决了,在这做个分享,对峰哥表达一下感激之情 网上搜索到的对“Truncated incorrect DO ...

  8. 初步学习大数据——设置虚拟机固定ip地址

    1.打开本机的网络连接 2.右键以太网,打开属性. 3.右键VMnet8,打开属性.最多不能超过255,最少不能小于0.    0~255之间. 4.找到你要设置固定IP地址的虚拟机 ,选择上方的编辑 ...

  9. winform文件筛选器

    在.net 框架中,微软给我们封装了一个用于打开文件的对话框——OpenFileDialog.而该对话框包含一个可以筛选文件的属性——Filter,利用该属性,可选筛选出我们需要的文件.   因此,我 ...

  10. Python数据挖掘(爬虫强化)

    (我喜欢雨天,因为雨天我可以回到童年踩水花!哈!) 2018年 --7月--12日 : 多云又暴雨 T—T 前言 我要把爬虫的终极利器介绍一下,这个只要是我们肉眼能看到的,就算在源码中或者在json中 ...