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.pswp.cn/news/285597.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285597.shtml
英文地址,請注明出處:http://en.pswp.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 上,先…