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 /// <summary> 2 /// 窗口显示变更触发时机 3 /// </summary> 4 public enum WindowLocationInvokeOccasion 5 { 6 /// <summary> 7 /// 只要Activated就显示在中间 8 /// </summary> 9 Activated = 0, 10 11 /// <summary> 12 /// 只在第一次Activated时,显示在中间一次,之后的变化就不修改 13 /// </summary> 14 FirstActivated, 15 16 /// <summary> 17 /// 窗口每次显示时,窗口居中 18 /// <para>可以解决单实例窗口弹出不居中问题</para> 19 /// </summary> 20 Visibile, 21 22 /// <summary> 23 /// 窗口每次显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中 24 /// <para>可以解决单实例窗口弹出不居中问题</para> 25 /// </summary> 26 VisibileInDifferentScreen, 27 28 /// <summary> 29 /// 不触发 30 /// </summary> 31 Defatult 32 }
如上枚举包含了4种触发机制。
我们再定义个附加属性,通过附加属性去设置窗口的额外功能-居中显示触发机制
1 /// <summary> 2 /// 窗口显示居中触发时机 3 /// <para>另:居中显示设置,请使用<see cref="Window"/>的<see cref="WindowStartupLocation"/>属性</para> 4 /// </summary> 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 /// <summary> 2 /// 在主窗口中居中显示 3 /// </summary> 4 /// <param name="subWindow"></param> 5 /// <param name="parentWindow"></param> 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 /// <summary> 2 /// 在父窗口所在屏幕居中显示 3 /// </summary> 4 /// <param name="subWindow"></param> 5 /// <param name="parentWindow"></param> 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 窗口居中 变更触发机制相关推荐
- 【Flink】Flink 多并行度下的 watermark触发机制
1.案例 /*** 测试点:测试多 多并行度下的 watermark触发机制* 参考:链接:https://juejin.im/post/5bf95810e51d452d705fef33** @thr ...
- qt 设置ui窗口为固定大小_Qt 设置窗口居中显示和窗体大小
设置窗口居中显示 方法一:在窗口(QWidget类及派生类)的构造函数中添加如下代码: #include //....... QDesktopWidget* desktop = QApplicatio ...
- WPF窗口长时间无人操作鼠标自动隐藏
原文:WPF窗口长时间无人操作鼠标自动隐藏 在软件开发中有时会有等待一段时间无人操作后隐藏鼠标,可能原因大致如下: 1.为了安全性,特别是那些需要用到用户名和密码登录服务端的程序,常常考虑长期无人操作 ...
- htmljavascript 事件触发机制
html 事件触发机制 <!DOCTYPE html> <html> <head><meta charset="UTF-8">< ...
- JavaScript弹出新窗口居中显示
JavaScript弹出新窗口居中显示 代码如下: <script language="javascript">function openWin(u, w, h) {v ...
- Windows API实现窗口居中
代码如下: //居中窗口int scrWidth, scrHeight;RECT rect;scrWidth = GetSystemMetrics(SM_CXSCREEN);scrHeight = G ...
- Mqtt paho 回调函数触发机制跟踪
Python Mqtt paho 回调函数触发机制跟踪,我使用的是 buildroot 里面的 mqtt paho , 代码在 ''' buildroot-2017.02.8/output/build ...
- 设置WPF窗口相对于非WPF窗口的位置
在前一个Post当中,指出了在WPF的WindowInteropHelper类中的一个BUG:通过WindowInteropHelper的Owner属性不能实现把WPF窗口的Owner属性设置为一个非 ...
- PyQt5 技术篇-QWidget、QDialog程序窗口关闭closeEvent()触发事件方法重写
我用 QWidget 来做个示例,它在程序窗口关闭时会触发 closeEvent() 事件,我们把它重写后就能实现关闭窗口时触发我们想要的效果. 重点就两个,如下所示: 重点一: 重写组件的 clos ...
最新文章
- 什么地方容易刷出ak_CSGO皮肤推荐——AK燃料喷射器
- LinCode落单的数
- php网站服务器500,php服务器错误500
- android studio 引入httpclient,HttpClient不会导入Android Studio
- python lncrna_分析指令备份.sh
- react学习笔记--一--移动端项目搭建
- 【系统分析师之路】2021年上系统分析师案例分析历年真题
- rdkit获得原子的标准排序序号
- css ol 序列样式:数字带圆圈、括号
- python平行四边形代码_python 已知平行四边形三个点,求第四个点的案例
- 【手把手 带你准备电赛】解答小课堂——串口通信和串行通信
- 知识付费,下半场怎么走(附大会PPT下载)
- 大数据用什么软件python_大数据软件 python
- 【云原生 | 从零开始学Kubernetes】十二、k8spod的生命周期与容器钩子
- 应届生如何准备校招,用我这一年的校招经历告诉你
- python小游戏之垃圾分类
- 计算机毕业设计ssm临沂旅游咨询系统
- Scrapy IT之家评论爬虫
- java9 gc log参数迁移_个人文章 - SegmentFault 思否
- 6万字解决算法面试中的深度学习基础问题
热门文章
- TimeLine CSS/Javascript 时间线
- 问题1 机器学习篇 如何解决过拟合(overfiting)?
- 解决WebClient或HttpWebRequest首次连接缓慢问题
- liunx 在虚拟机(VMware)下挂载光驱命令
- Oracle函数列表速查
- 路由器距离向量算法计算举例_距离向量路由选择是什么 距离向量路由选择原理介绍【图文】...
- 【数字信号处理】离散时间信号 ( 模拟信号、离散时间信号、数字信号 | 采样导致时间离散 | 量化导致幅度离散 )
- 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )
- 【Android 安全】使用 360 加固宝加固应用 ( 加固工具准备 | 生成签名 APK | 加固操作 | 反编译验证加固效果 )
- 【Android 安全】DEX 加密 ( Application 替换 | 获取 ContextImpl、ActivityThread、LoadedApk 类型对象 | 源码分析 )