WPF 窗口居中 & 变更触发机制

原文:WPF 窗口居中 & 变更触发机制

窗口居中 & 变更触发机制

解决:

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>
 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

原文地址:https://www.cnblogs.com/lonelyxmas/p/9091139.html

时间: 2024-08-08 12:28:18

WPF 窗口居中 & 变更触发机制的相关文章

vue 中监听窗口发生变化,触发监听事件, window.onresize &amp;&amp; window.addEventListener(&#39;resize&#39;,fn) ,window.onresize无效的处理方式

1 // 开始这样写,不执行 2 window.onresize = function() { 3 console.log('窗口发生变化') 4 } 5 6 7 // 改成window监听事件 8 window.addEventListener('resize', function() { 9 console.log('窗口发生变化') 10 }) onresize的定义方式 一.直接在html中定义 如<body onresize="doResize()"/> 二.直接

tmux 窗口自动变更名字

tmux 窗口自动变更名字的解决方案: 1. tmux.conf 里面更改 set-window-option -g automatic-rename off set-option -g allow-rename off  2. bashrc 里面更改: DISABLE_AUTO_TITLE=true

最近玩了一下qt5.2.1,顺着写点东西,关于这个版本设置程序主窗口居中

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <QtGui/QGuiApplication> #include <QDebug> #include <QScreen> #include "qtquick2applicationviewer.h" int main(int argc, char *argv[]) {     QGuiApplication app(arg

PYQT窗口居中

#UI.py,通过UI设计师制作后直接转换为UI.py脚本 # -*- coding: utf-8 -*-from PyQt4 import QtCore, QtGui try:    _fromUtf8 = QtCore.QString.fromUtf8except AttributeError:    _fromUtf8 = lambda s: s class Ui_Form(object):    def setupUi(self, Form):        Form.setObject

C#事件触发机制

C#的事件触发机制,类似于c++的回调函数机制 我先简单说一下,委托和事件的实质,后期再重开一篇博文来详细说 委托:指向方法的指针,类似于C的函数指针 事件:是一个可以存放0个或多个方法指针的数据结构  .......... 在一次编译后会为其生成一个类等等的就以后另开博文说了 看看触发机制 方便理解,来个通俗一点的图 事件触发源类 class cclass { private char i; public delegate void ichanged(cclass s); public eve

MFC 窗口居中显示 VS2010

MFC 窗口居中显示  VS2010 (2011-09-11 19:52:05) 转载▼ 标签: 窗口居中显示 it 分类: MFC MFC窗口居中显示   VS2010   工程名为:MFC22_6 目的:点击居中按钮,窗口将在文档的中央显示思路:使窗口居中显示可以调用CWnd::CenterWindow函数.void CenterWindow(CWnd* pAlternateOwner=NULL):步骤: 1.   用创建一个单文档应用程序 2.   添加一个对话框资源//(类视图 右键—添

ANDROID窗口管理服务实现机制和架构分析

 一.功能 窗口管理是ANDROID框架一个重要部分,主要包括如下功能: (1)Z-ordered的维护 (2)窗口的创建.销毁 (3)窗口的绘制.布局 (4)Token管理,AppToken (5)活动窗口管理(FocusWindow) (6)活动应用管理(FocusAPP) (7)输入法管理 (8)系统消息收集与分发 这些功能主要由一个窗口管理服务和相应的客户端来实现的,客户端通过BINDER机制与服务实现交互.       窗口管理服务端负责主要的窗口管理功能,由一个WindowMan

WPF 窗口自定义拉伸

使用win32 .NET技术交流群 199281001 .欢迎加入. 1 //自定义窗体拉伸 2 3 public HwndSource _HwndkaifaSource; 4 private const int WM_SYSCOMMAND = 0x112; 5 [DllImport("user32.dll", CharSet = CharSet.Auto)] 6 private static extern IntPtr SendMessage(IntPtr hWnd, uint Ms

WPF 窗口在右下角出现,识别分辨率

直接上代码. Point brp = SystemParameters.WorkArea.BottomRight;//当前桌面右下角的位置 WPF 窗口在右下角出现,识别分辨率