标签:stact AC turn reg tps 比例 sam ble 条件
原文:WPF 窗口居中 & 变更触发机制
窗口居中 & 变更触发机制
解决:
1。单实例窗口,窗口每次隐藏后再显示时,位置居中显示
2。多屏幕下单实例窗口,当父窗口移动到其它屏幕时,单实例窗口再次弹出时,位置才更新到父窗口屏幕。
3。子窗口每次唤醒时,都居中显示。
窗口首次显示的位置 - WindowStartupLocation
windows的启动时位置显示,WindowStartupLocation
- CenterOwner --显示在父窗口的中间(设置Owner)
- CenterScreen --显示在当前屏幕中间
- Manual --默认位置
当第一次window.ShowDialog时,window显示如上设置。
变更触发机制
上面只涉及到了首次显示位置,之后,窗口的位置会继续保留
- 如何设置窗口隐藏之后再次弹出时,显示在中间(CenterOwner/CenterScreen)?
- 如何设置窗口一直停留在显示在中间?
我们先了解一下,有哪些触发机制
- Activated 窗口激活
窗口变更为前台窗口时(即显示在最前面),会触发
- IsVisibleChanged 显示变更
当我们设置窗口隐藏Hide()时,IsVisibile=false.窗口再次ShowDialog时,IsVisibile=true;
利用如上俩种机制,下面就可以搞事情了。
首先定义几个枚举:
1 ///
2 /// 窗口显示变更触发时机
3 ///
4 public enum WindowLocationInvokeOccasion
5 {
6 ///
7 /// 只要Activated就显示在中间
8 ///
9 Activated = 0,
10
11 ///
12 /// 只在第一次Activated时,显示在中间一次,之后的变化就不修改
13 ///
14 FirstActivated,
15
16 ///
17 /// 窗口每次显示时,窗口居中
18 /// 可以解决单实例窗口弹出不居中问题
19 ///
20 Visibile,
21
22 ///
23 /// 窗口每次显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中
24 /// 可以解决单实例窗口弹出不居中问题
25 ///
26 VisibileInDifferentScreen,
27
28 ///
29 /// 不触发
30 ///
31 Defatult
32 }
如上枚举包含了4种触发机制。
我们再定义个附加属性,通过附加属性去设置窗口的额外功能-居中显示触发机制
1 ///
2 /// 窗口显示居中触发时机
3 /// 另:居中显示设置,请使用的属性
4 ///
5 public static readonly DependencyProperty InvokeOccasionProperty = DependencyProperty.RegisterAttached(
6 "InvokeOccasion", typeof(WindowLocationInvokeOccasion), typeof(WindowLocationOptions),
7 new PropertyMetadata(default(WindowLocationInvokeOccasion), InvokeOccasionProperty_ChangedCallback));
在属性更改触发事件中,根据不同的触发条件,设置不同的居中显示。
- Activated --只要Activated就显示在中间
每次触发,直接显示窗口即可
- 首次Activated
通过设置window.Activated -= ShowInCenter_Activated;禁用下次触发进入
- Visibile
- VisibileInDifferentScreen
窗口显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中.
怎么判断当前子窗口与父窗口是否在同一屏幕?
1 var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
2
3 Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
4 double dpiXRatio = currentGraphics.DpiX / 96;
5 double dpiYRatio = currentGraphics.DpiY / 96;
6
7 //当子窗口与父窗口所在屏幕相同时,不作处理
8 var isSubWindowInSameScreen = subWindow.Left > screen.Bounds.Left / dpiXRatio &&
9 subWindow.Left 10 subWindow.Top > screen.Bounds.Top / dpiYRatio &&
11 subWindow.Top dpiYRatio;
12 return isSubWindowInSameScreen;
介绍完成触发条件,下面说下窗口居中显示。
居中显示,分为当前屏幕内居中/主窗口内居中,直接上代码
1.在主窗口中居中显示-CenterOwner
设置窗口的依靠位置Location(Left,Top)(左上角)
-
子窗口最大化时 --WindowState=“Maximized”最大化窗口,固定的弹出到主屏幕,因此需额外处理,根据屏幕Location设置位置;
-
父窗口最大化时 --父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置
-
CenterOwner窗口居中显示 --直接取父窗口的位置/大小和子窗口的大小,进行计算即可
PS:窗口的位置Left/Top可能为负
1 ///
2 /// 在主窗口中居中显示
3 ///
4 ///
5 ///
6 private static void SetWindowInCenterOwner(Window subWindow, Window parentWindow)
7 {
8 //最大化窗口,固定的弹出到主屏幕,因此需额外处理
9 if (subWindow.WindowState == WindowState.Maximized)
10 {
11 //子窗口最大化时,需要根据屏幕设置位置;
12 var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
13
14 Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
15 double dpiXRatio = currentGraphics.DpiX / 96;
16 double dpiYRatio = currentGraphics.DpiY / 96;
17
18 subWindow.Left = screen.Bounds.Left / dpiXRatio;
19 subWindow.Top = screen.Bounds.Top / dpiYRatio;
20 }
21 if (parentWindow.WindowState == WindowState.Maximized)
22 {
23 //父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置
24 var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
25
26 Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
27 double dpiXRatio = currentGraphics.DpiX / 96;
28 double dpiYRatio = currentGraphics.DpiY / 96;
29
30 //窗口居中显示
31 subWindow.Left = screen.Bounds.Left / dpiXRatio +
32 (screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;
33 subWindow.Top = screen.Bounds.Top / dpiYRatio +
34 (screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;
35 }
36 else
37 {
38 //窗口居中显示
39 subWindow.Left = parentWindow.Left + (parentWindow.ActualWidth - subWindow.ActualWidth) / 2;
40 subWindow.Top = parentWindow.Top + (parentWindow.ActualHeight - subWindow.ActualHeight) / 2;
41 }
42 }
2.当前屏幕内居中-CenterScreen
窗口位置设置和上面的一样,值得注意的是DPI。
通过win的显示设置,调整文本显示比例,屏幕的位置转换(X,Y),得考虑DPI的换算
1 ///
2 /// 在父窗口所在屏幕居中显示
3 ///
4 ///
5 ///
6 private static void SetWindowInCenterScreen(Window subWindow, Window parentWindow)
7 {
8 SetWindowLocationInScreen(subWindow, parentWindow, subWindow.WindowState);
9 }
10
11 private const int DpiPercent = 96;
12
13 private static void SetWindowLocationInScreen(Window subWindow, Window parentWindow, WindowState windowState)
14 {
15 var intPtr = new WindowInteropHelper(parentWindow).Handle;
16 var screen = Screen.FromHandle(intPtr);
17
18 using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
19 {
20 double dpiXRatio = currentGraphics.DpiX / DpiPercent;
21 double dpiYRatio = currentGraphics.DpiY / DpiPercent;
22
23 if (windowState == WindowState.Maximized)
24 {
25 //设置全屏Location
26 subWindow.Left = screen.Bounds.Left / dpiXRatio;
27 subWindow.Top = screen.Bounds.Top / dpiYRatio;
28 }
29 else
30 {
31 //设置居中Location
32 subWindow.Left = screen.Bounds.Left / dpiXRatio +
33 (screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;
34 subWindow.Top = screen.Bounds.Top / dpiYRatio +
35 (screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;
36 }
37 }
38 }
关键字:单实例窗口,窗口居中,CenterOwner,CenterScreen,当前屏幕DPI
WPF 窗口居中 & 变更触发机制
标签:stact AC turn reg tps 比例 sam ble 条件
原文地址:https://www.cnblogs.com/lonelyxmas/p/9091139.html