WPF無邊框捕獲訊息改變視窗大小
阿新 • • 發佈:2018-11-08
原文:
WPF無邊框捕獲訊息改變視窗大小
OK,WndProc 註冊完成之後就可以通過 WndProc 函式完成對Windows訊息的處理了。可以發現,這裡的 WndProc 和標準的 Win32 訊息迴圈很像,只是多了一個 ref bool handled 引數,對於該引數MSDN是這樣說明的: 指示該訊息是否已處理的值。如果該訊息已處理,請將值設定為 true;否則請將其設定為 false。 在下面我們將會使用到這個引數數。
文章大部分轉載自http://blog.csdn.net/fwj380891124,如有問題,請聯絡刪除
最近一直在學習 WPF,看著別人做的WPF程式那麼漂亮,眼紅啊~ 很多漂亮的程式都是無邊框的。於是無邊框視窗操作就是最重要的了。無邊框視窗的操作一直以來相關的資料就很少。WPF 下的就更少了,有的大多是無邊框窗體的移動。在得到群裡高人的指點,再查了一些資料之後,終於把問題解決了。
廢話不多說,直接來看看如何實現吧!其實現原理很簡單:攔截並處理 Windows 訊息:WM_NCHITTEST。
WPF 處理 Windows 訊息的模式和 WinForm 不一樣了。Window 類裡沒有 WndProc 函數了,想要擷取 Windows 訊息必須藉助 HwndSource 新增 Hook。
- protected override void OnSourceInitialized(EventArgs e)
- {
- base.OnSourceInitialized(e);
- HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
- if (hwndSource != null)
- {
- hwndSource.AddHook(new
- }
- }
- protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
- {
- return IntPtr.Zero;
- }
OK,WndProc 註冊完成之後就可以通過 WndProc 函式完成對Windows訊息的處理了。可以發現,這裡的 WndProc 和標準的 Win32 訊息迴圈很像,只是多了一個 ref bool handled 引數,對於該引數MSDN是這樣說明的: 指示該訊息是否已處理的值。如果該訊息已處理,請將值設定為 true;否則請將其設定為 false。 在下面我們將會使用到這個引數數。
- private const int WM_NCHITTEST = 0x0084;
- private readonly int agWidth = 12; //拐角寬度
- private readonly int bThickness = 4; // 邊框寬度
- private Point mousePoint = new Point(); //滑鼠座標
- protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
- {
- switch (msg)
- {
- case WM_NCHITTEST:
- this.mousePoint.X = (lParam.ToInt32() &0xFFFF);
- this.mousePoint.Y = (lParam.ToInt32() >> 16);
- 測試滑鼠位置#region 測試滑鼠位置
- // 視窗左上角
- if (this.mousePoint.Y - this.Top <= this.agWidth
- && this.mousePoint.X - this.Left <= this.agWidth)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTTOPLEFT);
- }
- // 視窗左下角
- else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth
- && this.mousePoint.X - this.Left <= this.agWidth)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTBOTTOMLEFT);
- }
- // 視窗右上角
- else if (this.mousePoint.Y - this.Top <= this.agWidth
- && this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTTOPRIGHT);
- }
- // 視窗右下角
- else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth
- && this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTBOTTOMRIGHT);
- }
- // 視窗左側
- else if (this.mousePoint.X - this.Left <= this.bThickness)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTLEFT);
- }
- // 視窗右側
- else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.bThickness)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTRIGHT);
- }
- // 視窗上方
- else if (this.mousePoint.Y - this.Top <= this.bThickness)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTTOP);
- }
- // 視窗下方
- else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.bThickness)
- {
- handled = true;
- return new IntPtr((int)HitTest.HTBOTTOM);
- }
- else // 視窗移動
- {
- handled = true;
- return new IntPtr((int)HitTest.HTCAPTION);
- }
- #endregion
- }
- return IntPtr.Zero;
- }
從上面的程式碼可以看出,工作原理很簡單:擷取 WM_NCHITTEST 訊息,獲得滑鼠座標,再在你希望的地方返回不同的訊息以模擬滑鼠的狀態即可。需要注意的是,返回訊息之前必須將handled 設為 true。告訴系統你已經處理過該訊息,不然無效果。
關於 HitTest 是自定義的列舉類,裡面包含了滑鼠的各種訊息。
- 1public enum HitTest:int
- {
- HTERROR = -2,
- HTTRANSPARENT = -1,
- HTNOWHERE = 0,
- HTCLIENT = 1,
- HTCAPTION = 2,
- HTSYSMENU = 3,
- HTGROWBOX = 4,
- HTSIZE = HTGROWBOX,
- HTMENU = 5,
- HTHSCROLL = 6,
- HTVSCROLL = 7,
- HTMINBUTTON = 8,
- HTMAXBUTTON = 9,
- HTLEFT = 10,
- HTRIGHT = 11,
- HTTOP = 12,
- HTTOPLEFT = 13,
- HTTOPRIGHT = 14,
- HTBOTTOM = 15,
- HTBOTTOMLEFT = 16,
- HTBOTTOMRIGHT = 17,
- HTBORDER = 18,
- HTREDUCE = HTMINBUTTON,
- HTZOOM = HTMAXBUTTON,
- HTSIZEFIRST = HTLEFT,
- HTSIZELAST = HTBOTTOMRIGHT,
- HTOBJECT = 19,
- HTCLOSE = 20,
- HTHELP = 21,
- }
- HTBORDER 在不具有可變大小邊框的視窗的邊框上。
· HTBOTTOM 在視窗的水平邊框的底部。
· HTBOTTOMLEFT 在視窗邊框的左下角。
· HTBOTTOMRIGHT 在視窗邊框的右下角。
· HTCAPTION 在標題條中。
· HTCLIENT 在客戶區中。
· HTERROR 在螢幕背景或視窗之間的分隔線上(與HTNOWHERE相同,除了Windows的DefWndProc函式產生一個系統響聲以指明錯誤)。
· HTGROWBOX 在尺寸框中。
· HTHSCROLL 在水平滾動條上。
· HTLEFT 在視窗的左邊框上。
· HTMAXBUTTON 在最大化按鈕上。
· HTMENU 在選單區域。
· HTMINBUTTON 在最小化按鈕上。
· HTNOWHERE 在螢幕背景或視窗之間的分隔線上。
· HTREDUCE 在最小化按鈕上。
· HTRIGHT 在視窗的右邊框上。
· HTSIZE 在尺寸框中。(與HTGROWBOX相同)
· HTSYSMENU 在控制選單或子視窗的關閉按鈕上。
· HTTOP 在視窗水平邊框的上方。
· HTTOPLEFT 在視窗邊框的左上角。
· HTTOPRIGHT 在視窗邊框的右上角。
· HTTRANSPARENT 在一個被其它視窗覆蓋的視窗中。
· HTVSCROLL 在垂直滾動條中。
· HTZOOM 在最大化按鈕上。