WPF 窗口居中 变更触发机制

本文经原作者授权以原创方式二次分享,欢迎转载、分享。

原文作者:唐宋元明清

原文地址:https://www.cnblogs.com/kybs0/p/7420767.html

窗口居中 & 变更触发机制

解决:

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

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

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

窗口首次显示的位置 - WindowStartupLocation

Windows的启动时位置显示,WindowStartupLocation

  • CenterOwner --显示在父窗口的中间(设置Owner)

  • CenterScreen --显示在当前屏幕中间

  • Manual --默认位置 当第一次Window.ShowDialog时,window显示如上设置。

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

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

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

  • Activated 窗口激活 窗口变更为前台窗口时(即显示在最前面),会触发

  • IsVisibleChanged 显示变更 当我们设置窗口隐藏Hide()时,IsVisibile=false.窗口再次ShowDialog时,IsVisibile=true; 利用如上俩种机制,下面就可以搞事情了。

首先定义几个枚举:

/// <summary>/// 窗口显示变更触发时机/// </summary>public enum WindowLocationInvokeOccasion{/// <summary>/// 只要Activated就显示在中间/// </summary>Activated = 0,/// <summary>/// 只在第一次Activated时,显示在中间一次,之后的变化就不修改/// </summary>FirstActivated,/// <summary>/// 窗口每次显示时,窗口居中/// <para>可以解决单实例窗口弹出不居中问题</para>/// </summary>Visibile,/// <summary>/// 窗口每次显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中/// <para>可以解决单实例窗口弹出不居中问题</para>/// </summary>VisibileInDifferentScreen,/// <summary>/// 不触发/// </summary>Defatult}

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

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

/// <summary>
/// 窗口显示居中触发时机
/// <para>另:居中显示设置,请使用<see cref="Window"/>的<see cref="WindowStartupLocation"/>属性</para>
/// </summary>
public static readonly DependencyProperty InvokeOccasionProperty = DependencyProperty.RegisterAttached("InvokeOccasion", typeof(WindowLocationInvokeOccasion), typeof(WindowLocationOptions),new PropertyMetadata(default(WindowLocationInvokeOccasion), InvokeOccasionProperty_ChangedCallback));

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

  • Activated --只要Activated就显示在中间 每次触发,直接显示窗口即可;

  • 首次Activated通过设置Window.Activated -= ShowInCenter_Activated;禁用下次触发进入

  • Visibile

  • VisibileInDifferentScreen窗口显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中. 怎么判断当前子窗口与父窗口是否在同一屏幕?

var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
double dpiXRatio = currentGraphics.DpiX / 96;
double dpiYRatio = currentGraphics.DpiY / 96;//当子窗口与父窗口所在屏幕相同时,不作处理
var isSubWindowInSameScreen = subWindow.Left > screen.Bounds.Left / dpiXRatio &&subWindow.Left < screen.Bounds.Left / dpiXRatio + screen.Bounds.Width / dpiXRatio &&subWindow.Top > screen.Bounds.Top / dpiYRatio &&subWindow.Top < screen.Bounds.Top / dpiYRatio + screen.Bounds.Height / dpiYRatio;
return isSubWindowInSameScreen;

绍完成触发条件,下面说下窗口居中显示。居中显示,分为当前屏幕内居中/主窗口内居中,直接上代码

1)在主窗口中居中显示-CenterOwner 设置窗口的依靠位置Location(Left,Top)(左上角)

  • 子窗口最大化时 --WindowState=“Maximized”最大化窗口,固定的弹出到主屏幕,因此需额外处理,根据屏幕Location设置位置;

  • 父窗口最大化时 --父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置

  • CenterOwner窗口居中显示 --直接取父窗口的位置/大小和子窗口的大小,进行计算即可;
    PS:窗口的位置Left/Top可能为负

/// <summary>
/// 在主窗口中居中显示
/// </summary>
/// <param name="subWindow"></param>
/// <param name="parentWindow"></param>
private static void SetWindowInCenterOwner(Window subWindow, Window parentWindow)
{//最大化窗口,固定的弹出到主屏幕,因此需额外处理if (subWindow.WindowState == WindowState.Maximized){//子窗口最大化时,需要根据屏幕设置位置;var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);double dpiXRatio = currentGraphics.DpiX / 96;double dpiYRatio = currentGraphics.DpiY / 96;subWindow.Left = screen.Bounds.Left / dpiXRatio;subWindow.Top = screen.Bounds.Top / dpiYRatio;}if (parentWindow.WindowState == WindowState.Maximized){//父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);double dpiXRatio = currentGraphics.DpiX / 96;double dpiYRatio = currentGraphics.DpiY / 96;//窗口居中显示subWindow.Left = screen.Bounds.Left / dpiXRatio +(screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;subWindow.Top = screen.Bounds.Top / dpiYRatio +(screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;}else{//窗口居中显示subWindow.Left = parentWindow.Left + (parentWindow.ActualWidth - subWindow.ActualWidth) / 2;subWindow.Top = parentWindow.Top + (parentWindow.ActualHeight - subWindow.ActualHeight) / 2;}
}

2)当前屏幕内居中-CenterScreen;

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

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

/// <summary>
/// 在父窗口所在屏幕居中显示
/// </summary>
/// <param name="subWindow"></param>
/// <param name="parentWindow"></param>
private static void SetWindowInCenterScreen(Window subWindow, Window parentWindow)
{SetWindowLocationInScreen(subWindow, parentWindow, subWindow.WindowState);
}private const int DpiPercent = 96;private static void SetWindowLocationInScreen(Window subWindow, Window parentWindow, WindowState windowState)
{var intPtr = new WindowInteropHelper(parentWindow).Handle;var screen = Screen.FromHandle(intPtr);using (Graphics currentGraphics = Graphics.FromHwnd(intPtr)){double dpiXRatio = currentGraphics.DpiX / DpiPercent;double dpiYRatio = currentGraphics.DpiY / DpiPercent;if (windowState == WindowState.Maximized){//设置全屏LocationsubWindow.Left = screen.Bounds.Left / dpiXRatio;subWindow.Top = screen.Bounds.Top / dpiYRatio;}else{//设置居中LocationsubWindow.Left = screen.Bounds.Left / dpiXRatio +(screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;subWindow.Top = screen.Bounds.Top / dpiYRatio +(screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285597.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]5分钟实现Android中更换头像功能

5分钟实现Android中更换头像功能 写在前面&#xff1a; 更换头像这个功能在用户界面几乎是100%出现的。通过拍摄照片或者调用图库中的图片&#xff0c;并且进行剪裁&#xff0c;来进行头像的设置。 功能相关截图如下&#xff1a; 下面我们直接看看完整吧&#xff1a; public cl…

Excel VBA窗体上打印系统时间print now出错原因及解决方案

如图所示,需要在窗体上显示当前系统时间: 首先,我们看一下now函数的原型: Now 函数   语法:Now   说明:返回一个 Variant (Date),根据计算机系统设置的日期和时间来指定日期和时间。   示例: Private Sub CommandButton1_Click()Dim a As Varianta = NowMsgBox…

(第九周)团队项目14

项目名&#xff1a;食物链教学工具 组名&#xff1a;奋斗吧兄弟 组长&#xff1a;黄兴 组员&#xff1a;李俞寰、杜桥、栾骄阳、王东涵 代码地址&#xff1a;HTTPS: https://git.coding.net/li_yuhuan/FoodChain.git SSH: gitgit.coding.net:li_yuhuan/FoodChain.git SCRUM会议…

为什么 C# 访问 null 字段会抛异常?

一&#xff1a;背景 1. 一个有趣的话题最近在看 硬件异常 相关知识&#xff0c;发现一个有意思的空引用异常问题&#xff0c;拿出来和大家分享一下&#xff0c;为了方便讲述&#xff0c;先上一段有问题的代码。namespace ConsoleApp2 {internal class Program{static Person pe…

Android项目实战(十五):自定义不可滑动的ListView和GridView

不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView {public NoScrollListView(Context context, AttributeSet attrs) {super(context,attrs);}public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int mExpandSpec …

C语言试题一百之输入某年某月某日,判断这一天是这一年的第几天

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入某年某月某日,判断这一天是这一年的第几天? 分析: 以 3 月 5 日为例,应该先把…

[转]Java学习路线图(完整详细2019版)

一门永不过时的编程语言——Java 软件开发。 Java编程语言占比&#xff1a; 据官方数据统计&#xff0c;在全球编程语言工程师的数量上&#xff0c;Java编程语言以1000万的程序员数量位居首位。 而且很多软件的开发都离不开Java编程&#xff0c;因此其程序员的数量最多。而在…

【CASS精品教程】Win7+CAD2008+CASS9.1(含CASS3D)完美安装教程(附完整软件安装包下载)

本文讲解win764位系统上安装CAD2008+CASS9.1(含CASS3D)免费版安装,文末附完整软件下载地址,亲测可用!!! 文章目录 1. CAD2008安装2. CASS9.1安装3. 软件下载地址1. CAD2008安装 双击安装包中的Setup.exe,开始安装。 点击【安装产品】。

(十一)Jmeter另一种调试工具 HTTP Mirror Server

之前我介绍过Jmeter的一种调试工具Debug Sampler&#xff0c;它可以输出Jmeter的变量、属性甚至是系统属性而不用发送真实的请求到服务器。既然这样&#xff0c;那么HTTP Mirror Server又是做什么用的呢&#xff1f; 一、HTTP Mirror Server的作用&#xff1a; 它可以在本地临…

C语言九十八之实现企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万元,低于 20 万元时,低于 10 万元的部分按 10%提成,高于 10 万元的

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万…

[转]大数据环境搭建步骤详解(Hadoop,Hive,Zookeeper,Kafka,Flume,Hbase,Spark等安装与配置)

大数据环境安装和配置&#xff08;Hadoop2.7.7&#xff0c;Hive2.3.4&#xff0c;Zookeeper3.4.10&#xff0c;Kafka2.1.0&#xff0c;Flume1.8.0&#xff0c;Hbase2.1.1&#xff0c;Spark2.4.0等&#xff09; 系统说明搭建步骤详述 一、节点基础配置 二、Hadoop安装和配置三、…

C# Any()和AII()方法

我们常常需要的另一类查询是确定数据是否满足某个条件&#xff0c;或者确保所有数据都满足某个条件。例如&#xff0c;需要确定某个产品是否已经脱销(库存为 0)&#xff0c;或者是否发生了某个交易。LINQ 提供了两个布尔方法&#xff1a;Any()和 All()&#xff0c;它们可以快速…

树状数组 + 位运算 LA 4013 A Sequence of Numbers

题目传送门 题意&#xff1a;n个数&#xff0c;两种操作&#xff0c;一是每个数字加x&#xff0c;二是查询& (1 << T) 1 的个数 分析&#xff1a;因为累加是永远的&#xff0c;所以可以离线处理。树状数组点是c[16][M] 表示数字x%(1 << j) 后的数字pos&#x…

【地理信息系统GIS】教案(七章全)第七章:3S技术综合应用

文章目录 第一节 3S技术概述第二节 GIS与RS的综合应用第三节 GIS与GPS的综合应用第四节 网络GIS的综合应用第一节 3S技术概述 1.什么是“3S” 技术? 遥感(Remote Sensing ,RS); 地理信息系统(Geographical information System ,GIS); 全球定位系统(Global Positio…

初级图像混合——线性混合操作

addWeighted函数 这个函数的作用是&#xff0c;计算两个数组&#xff08;图像阵列&#xff09;的加权和。原型如下&#xff1a; void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype-1); 第一个参数&am…

C语言九十九之实现一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多少?

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 一、题目 一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多…

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一)

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(四) 【专升本计算机】2021…

快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码

这是 ASP.NET Core Identity 系列的第四篇文章&#xff0c;上一篇文章讲解了如何在 ASP.NET Core Identity 中实现用户登录与登出。这篇文章讲一讲如何在 ASP.NET Core Identity 中通过邮件服务实现用户账号的密码重置。点击上方或后方蓝字&#xff0c;阅读 ASP.NET Core Ident…

[.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...

[.net 面向对象程序设计深入]&#xff08;4&#xff09;MVC 6 ——谈谈MVC的版本变迁及新版本6.0发展方向 1.关于MVC 在本篇中不再详细介绍MVC的基础概念&#xff0c;这些东西百度要比我写的全面多了&#xff0c;MVC从1.0到5.0的时间也不短了&#xff0c;很多人只是按照范例去使…

C语言试题101之输入三个整数 x,y,z,请把这三个数由小到大输出

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入三个整数 x,y,z,请把这三个数由小到大输出 分析:想办法把最小的数放到 x 上,先…