ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WPF 窗体自适应

2022-07-29 13:36:50  阅读:202  来源: 互联网

标签:窗口 double 高度 适应 window 窗体 var WPF 屏幕


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

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

界面设置
设置窗口内容自适应SizeToContent="WidthAndHeight"
添加ViewBox -- 设置默认不拉伸Stretch="None",当DPI超大时如超过1920*1080p的175%(即win10默认不支持的比例显示),开启ViewBox缩放
顶层布局容器RootGrid添加高宽最大值和最小值。
1 <Window x:Class="WindowHeightChangedForDpi.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:WindowHeightChangedForDpi"
7 mc:Ignorable="d"
8 Title="MainWindow" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen">
9
10
11
12

13

14
后台设置 - 窗口大小自适应设置
添加对Loaded事件的监听,并在之后注销。窗口只需要首次初始其高度即可。
获取屏幕的高度和任务栏的高度 -- 具体可以参考C# 获取当前屏幕的宽高和位置
比较当前可显示高度(屏幕高度-任务栏高度)与窗口的最大/最小高度,然后设置当前窗口的实际高度。
如果可显示高度比最小值还小,则开启ViewBox内容缩放。ViewBox的高度为当前可显示高度。
如果当前窗口有阴影,可设置阴影高度大小。保证窗口在可显示区域内正常显示。
1 public partial class MainWindow : Window
2 {
3 public MainWindow()
4 {
5 InitializeComponent();
6 Loaded += InitWindowActualHeight_OnLoaded;
7 }
8
9 #region 设置窗口对屏幕高度的自适应
10
11 private void InitWindowActualHeight_OnLoaded(object sender, RoutedEventArgs e)
12 {
13 Loaded -= InitWindowActualHeight_OnLoaded;
14 InitWindowActualHeight();
15 }
16
17 private const double WindowShadowHeight = 0;
18
19 private void InitWindowActualHeight()
20 {
21 //获取窗体所在屏幕的高度
22 var visibleAreaHeight = GetScreenHeight();
23
24 //可显示高度 > 窗口最大高度
25 if (visibleAreaHeight > RootGrid.MaxHeight + WindowShadowHeight)
26 {
27 //设置高度等于最大高度
28 RootGrid.Height = RootGrid.MaxHeight;
29 }
30 //可显示高度 < 窗口最小高度
31 else if (visibleAreaHeight < RootGrid.MinHeight + WindowShadowHeight)
32 {
33 //设置Viewbox高度=可视高度-阴影高度(此处通过绽放显示窗口,所以不能通过设置窗口或者设置内容的高度来实现)
34 RootViewbox.Height = visibleAreaHeight - WindowShadowHeight;
35 //等比例缩小
36 RootViewbox.Stretch = Stretch.Uniform;
37 }
38 else
39 {
40 //设置高度等于最小高度
41 RootGrid.Height = RootGrid.MinHeight;
42 }
43 }
44 const double DpiPercent = 96;
45 private double GetScreenHeight()
46 {
47 var intPtr = new WindowInteropHelper(this).Handle;//获取当前窗口的句柄
48 var screen = Screen.FromHandle(intPtr);//获取当前屏幕
49
50 double height = 0;
51 using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
52 {
53 double dpiXRatio = currentGraphics.DpiX / DpiPercent;
54 double dpiYRatio = currentGraphics.DpiY / DpiPercent;
55 height = screen.WorkingArea.Height / dpiYRatio;
56 //var width = screen.WorkingArea.Width / dpiXRatio;
57 //var left = screen.WorkingArea.Left / dpiXRatio;
58 //var top = screen.WorkingArea.Top / dpiYRatio;
59 }
60 return height;
61 }
62 #endregion
63 }
注:获取的屏幕高度为屏幕像素,需要转换为WPF单位。

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

下载Demo

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

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

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

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

1 <Window x:Class="WindowSizeToScreenRatioDisplay.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:WindowSizeToScreenRatioDisplay"
7 mc:Ignorable="d"
8 Title="MainWindow"
9 local:WindowAdaptation.WidthByScreenRatio="0.8" MaxWidth="1200" MinWidth="800"
10 local:WindowAdaptation.HeightByScreenRatio="0.75" MaxHeight="800" MinHeight="520">
11
12
13

14
添加附加属性 WidthByScreenRatio、HeightByScreenRatio。

控制窗口大小:

默认设置为当前屏幕工作区域的显示比例大小
如果超过窗口最大高度/宽高,则显示为窗口最大高度/宽高
如果小于窗口最小高度/宽高,则显示为当前可显示区域的最大高度/宽高
1 ///


2 /// 为窗口添加附加属性的辅助类
3 ///

4 public class WindowAdaptation
5 {
6 #region 窗口宽度比例
7 ///
8 /// 窗口宽度比例 单位:小数(0 - 1.0]
9 /// 窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例
10 ///

11 public static readonly DependencyProperty WidthByScreenRatioProperty = DependencyProperty.RegisterAttached(
12 "WidthByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnWidthByScreenRatioPropertyChanged));
13
14 private static void OnWidthByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
15 {
16 if (d is Window window && e.NewValue is double widthByScreenRatio)
17 {
18 if (widthByScreenRatio <= 0 || widthByScreenRatio > 1)
19 {
20 throw new ArgumentException($"屏幕比例不支持{widthByScreenRatio}");
21 }
22
23 var screenDisplayArea = GetScreenSize(window);
24 var screenRatioWidth = screenDisplayArea.Width * widthByScreenRatio;
25
26 if (!double.IsNaN(window.MaxWidth) && screenRatioWidth > window.MaxWidth)
27 {
28 window.Width = window.MaxWidth;
29 }
30 else if (!double.IsNaN(window.MinWidth) && screenRatioWidth < window.MinWidth)
31 {
32 window.Width = screenDisplayArea.Width;
33 }
34 else
35 {
36 window.Width = screenRatioWidth;
37 }
38 }
39 }
40
41 public static void SetWidthByScreenRatio(DependencyObject element, double value)
42 {
43 element.SetValue(WidthByScreenRatioProperty, value);
44 }
45
46 public static double GetWidthByScreenRatio(DependencyObject element)
47 {
48 return (double)element.GetValue(WidthByScreenRatioProperty);
49 }
50 #endregion
51
52 #region 窗口高度比例
53 ///
54 /// 窗口宽度比例 单位:小数(0 - 1.0]
55 /// 窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例
56 ///

57 public static readonly DependencyProperty HeightByScreenRatioProperty = DependencyProperty.RegisterAttached(
58 "HeightByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnHeightByScreenRatioPropertyChanged));
59
60 private static void OnHeightByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
61 {
62 if (d is Window window && e.NewValue is double heightByScreenRatio)
63 {
64 if (heightByScreenRatio <= 0 || heightByScreenRatio > 1)
65 {
66 throw new ArgumentException($"屏幕比例不支持{heightByScreenRatio}");
67 }
68
69 var screenDisplayArea = GetScreenSize(window);
70 var screenRatioHeight = screenDisplayArea.Height * heightByScreenRatio;
71
72 if (!double.IsNaN(window.MaxHeight) && screenRatioHeight > window.MaxHeight)
73 {
74 window.Height = window.MaxHeight;
75 }
76 else if (!double.IsNaN(window.MinHeight) && screenRatioHeight < window.MinHeight)
77 {
78 window.Height = screenDisplayArea.Height;
79 }
80 else
81 {
82 window.Height = screenRatioHeight;
83 }
84 }
85 }
86
87 public static void SetHeightByScreenRatio(DependencyObject element, double value)
88 {
89 element.SetValue(HeightByScreenRatioProperty, value);
90 }
91
92 public static double GetHeightByScreenRatio(DependencyObject element)
93 {
94 return (double)element.GetValue(HeightByScreenRatioProperty);
95 }
96 #endregion
97
98 const int DpiPercent = 96;
99 private static dynamic GetScreenSize(Window window)
100 {
101 var intPtr = new WindowInteropHelper(window).Handle;//获取当前窗口的句柄
102 var screen = Screen.FromHandle(intPtr);//获取当前屏幕
103 using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
104 {
105 //分别获取当前屏幕X/Y方向的DPI
106 double dpiXRatio = currentGraphics.DpiX / DpiPercent;
107 double dpiYRatio = currentGraphics.DpiY / DpiPercent;
108
109 var width = screen.WorkingArea.Width / dpiXRatio;
110 var height = screen.WorkingArea.Height / dpiYRatio;
111
112 return new { Width = width, Height = height };
113 }
114 }
115 }
下载 Demo

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

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

标签:窗口,double,高度,适应,window,窗体,var,WPF,屏幕
来源: https://www.cnblogs.com/LCLBook/p/16531932.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有