添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。 窗口居中 & 变更触发机制 解决: 1。单实例窗口,窗口每次隐藏后再显示时,位置居中显示 2。多屏幕下单实例窗口,当父窗口移动到其它屏幕时,单实例窗口再次弹出时,位置才更新到父窗口屏幕。 3。子窗口每次唤醒时,都居中显示。

窗口居中 & 变更触发机制

解决:

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///<summary> 2/// 窗口显示变更触发时机
 3///</summary> 4publicenum WindowLocationInvokeOccasion
 6///<summary> 7/// 只要Activated就显示在中间
 8///</summary> 9         Activated = 0,
1011///<summary>12/// 只在第一次Activated时,显示在中间一次,之后的变化就不修改
13///</summary>14        FirstActivated,
1516///<summary>17/// 窗口每次显示时,窗口居中
18///<para>可以解决单实例窗口弹出不居中问题</para>19///</summary>20        Visibile,
2122///<summary>23/// 窗口每次显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中
24///<para>可以解决单实例窗口弹出不居中问题</para>25///</summary>26        VisibileInDifferentScreen,
2728///<summary>29/// 不触发
30///</summary>31        Defatult
32     }

如上枚举包含了4种触发机制。

我们再定义个附加属性,通过附加属性去设置窗口的额外功能- 居中显示触发机制

1///<summary>2/// 窗口显示居中触发时机
3///<para>另:居中显示设置,请使用<see cref="Window"/><see cref="WindowStartupLocation"/>属性</para>4///</summary>5publicstaticreadonly DependencyProperty InvokeOccasionProperty = DependencyProperty.RegisterAttached(
6"InvokeOccasion", typeof(WindowLocationInvokeOccasion), typeof(WindowLocationOptions),
7new PropertyMetadata(default(WindowLocationInvokeOccasion), InvokeOccasionProperty_ChangedCallback));

在属性更改触发事件中,根据不同的触发条件,设置不同的居中显示。

  • Activated --只要Activated就显示在中间
    每次触发,直接显示窗口即可
  • 首次Activated
    通过设置window.Activated -= ShowInCenter_Activated;禁用下次触发进入
  • Visibile
  • VisibileInDifferentScreen
    窗口显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中.
    怎么判断当前子窗口与父窗口是否在同一屏幕?
 1var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
 2 3 Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
 4double dpiXRatio = currentGraphics.DpiX / 96;
 5double dpiYRatio = currentGraphics.DpiY / 96;
 6 7//当子窗口与父窗口所在屏幕相同时,不作处理 8var 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;
12return 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> 6privatestaticvoid SetWindowInCenterOwner(Window subWindow, Window parentWindow)
 8//最大化窗口,固定的弹出到主屏幕,因此需额外处理 9if (subWindow.WindowState == WindowState.Maximized)
11//子窗口最大化时,需要根据屏幕设置位置;12var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
1314         Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
15double dpiXRatio = currentGraphics.DpiX / 96;
16double dpiYRatio = currentGraphics.DpiY / 96;
1718         subWindow.Left = screen.Bounds.Left / dpiXRatio;
19         subWindow.Top = screen.Bounds.Top / dpiYRatio;
21if (parentWindow.WindowState == WindowState.Maximized)
23//父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置24var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
2526         Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
27double dpiXRatio = currentGraphics.DpiX / 96;
28double dpiYRatio = currentGraphics.DpiY / 96;
2930//窗口居中显示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;
36else37    {
38//窗口居中显示39         subWindow.Left = parentWindow.Left + (parentWindow.ActualWidth - subWindow.ActualWidth) / 2;
40         subWindow.Top = parentWindow.Top + (parentWindow.ActualHeight - subWindow.ActualHeight) / 2;
42 }

2.当前屏幕内居中-CenterScreen

窗口位置设置和上面的一样,值得注意的是DPI。

通过win的显示设置,调整文本显示比例,屏幕的位置转换(X,Y),得考虑DPI的换算

 1///<summary> 2/// 在父窗口所在屏幕居中显示
 3///</summary> 4///<param name="subWindow"></param> 5///<param name="parentWindow"></param> 6privatestaticvoid SetWindowInCenterScreen(Window subWindow, Window parentWindow)
 8    SetWindowLocationInScreen(subWindow, parentWindow, subWindow.WindowState);
1011privateconstint DpiPercent = 96;
1213privatestaticvoid SetWindowLocationInScreen(Window subWindow, Window parentWindow, WindowState windowState)
15var intPtr = new WindowInteropHelper(parentWindow).Handle;
16var screen = Screen.FromHandle(intPtr);
1718using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
20double dpiXRatio = currentGraphics.DpiX / DpiPercent;
21double dpiYRatio = currentGraphics.DpiY / DpiPercent;
2223if (windowState == WindowState.Maximized)
25//设置全屏Location26             subWindow.Left = screen.Bounds.Left / dpiXRatio;
27             subWindow.Top = screen.Bounds.Top / dpiYRatio;
29else30        {
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;
38 }

关键字:单实例窗口,窗口居中,CenterOwner,CenterScreen,当前屏幕DPI

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。