博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF 窗口居中 & 变更触发机制
阅读量:6580 次
发布时间:2019-06-24

本文共 6132 字,大约阅读时间需要 20 分钟。

原文:

窗口居中 & 变更触发机制

解决:

1。单实例窗口,窗口每次隐藏后再显示时,位置居中显示

2。多屏幕下单实例窗口,当父窗口移动到其它屏幕时,单实例窗口再次弹出时,位置才更新到父窗口屏幕。

3。子窗口每次唤醒时,都居中显示。

窗口首次显示的位置 - WindowStartupLocation

windows的启动时位置显示,WindowStartupLocation

  • CenterOwner --显示在父窗口的中间(设置Owner)
  • CenterScreen --显示在当前屏幕中间
  • Manual --默认位置

当第一次window.ShowDialog时,window显示如上设置。

变更触发机制

上面只涉及到了首次显示位置,之后,窗口的位置会继续保留

  • 如何设置窗口隐藏之后再次弹出时,显示在中间(CenterOwner/CenterScreen)?
  • 如何设置窗口一直停留在显示在中间?

我们先了解一下,有哪些触发机制

  1. Activated 窗口激活
    窗口变更为前台窗口时(即显示在最前面),会触发
  2. 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 Defatult32 }

如上枚举包含了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 < screen.Bounds.Left / dpiXRatio + screen.Bounds.Width / dpiXRatio &&10                                 subWindow.Top > screen.Bounds.Top / dpiYRatio &&11                                 subWindow.Top < screen.Bounds.Top / dpiYRatio + screen.Bounds.Height / 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     else37     {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             //设置全屏Location26             subWindow.Left = screen.Bounds.Left / dpiXRatio;27             subWindow.Top = screen.Bounds.Top / dpiYRatio;28         }29         else30         {31             //设置居中Location32             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

转载地址:http://fqnno.baihongyu.com/

你可能感兴趣的文章
ubuntu 16.04 安装PhpMyAdmin
查看>>
安卓开启多个服务
查看>>
设置分录行按钮监听事件
查看>>
C Primer Plus 第5章 运算符、表达式和语句 5.2基本运算符
查看>>
java并发库之Executors常用的创建ExecutorService的几个方法说明
查看>>
23种设计模式(1):单例模式
查看>>
socket 编程入门教程(五)UDP原理:4、“有连接”的UDP
查看>>
Jquery获取iframe中的元素
查看>>
Laravel 学习笔记5.3之 Query Builder 源码解析(下)
查看>>
Struts2简单入门实例
查看>>
2012CSDN年度博客之星评选http://vote.blog.csdn.net/item/blogstar/xyz_lmn
查看>>
BZOJ 4037 [HAOI2015]数字串拆分 ——动态规划
查看>>
SpringBoot实战总汇--详解
查看>>
2018年7月1日笔记
查看>>
尝试使用iReport4.7(基于Ubuntu Desktop 12.04 LTS)
查看>>
动态规划:金矿模型
查看>>
子元素应该margin-top为何会影响父元素【转】
查看>>
AJAX 状态值(readyState)与状态码(status)详解
查看>>
BZOJ3668:[NOI2014]起床困难综合症(贪心)
查看>>
LightOJ 1245(Harmonic Number (II))
查看>>