WPF无边框捕获消息改变窗口大小

简介: 原文:WPF无边框捕获消息改变窗口大小 文章大部分转载自http://blog.csdn.net/fwj380891124,如有问题,请联系删除  最近一直在学习 WPF,看着别人做的WPF程序那么漂亮,眼红啊~ 很多漂亮的程序都是无边框的。
原文: WPF无边框捕获消息改变窗口大小

文章大部分转载自http://blog.csdn.net/fwj380891124,如有问题,请联系删除


 最近一直在学习 WPF,看着别人做的WPF程序那么漂亮,眼红啊~ 很多漂亮的程序都是无边框的。于是无边框窗口操作就是最重要的了。无边框窗口的操作一直以来相关的资料就很少。WPF 下的就更少了,有的大多是无边框窗体的移动。在得到群里高人的指点,再查了一些资料之后,终于把问题解决了。

      废话不多说,直接来看看如何实现吧!其实现原理很简单:拦截并处理 Windows 消息:WM_NCHITTEST。

      WPF 处理 Windows 消息的模式和 WinForm 不一样了。Window 类里没有 WndProc 函数了,想要截取 Windows 消息必须借助 HwndSource 添加 Hook。

  1. protected override void OnSourceInitialized(EventArgs e)  
  2. {  
  3.     base.OnSourceInitialized(e);  
  4.     HwndSource hwndSource = PresentationSource.FromVisual(thisas HwndSource;  
  5.     if (hwndSource != null)  
  6.     {  
  7.         hwndSource.AddHook(new HwndSourceHook(this.WndProc));  
  8.     }  
  9. }  
  10.   
  11. protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)  
  12. {  
  13.     return IntPtr.Zero;  
  14. }  

    OK,WndProc 注册完成之后就可以通过 WndProc 函数完成对Windows消息的处理了。可以发现,这里的 WndProc 和标准的 Win32 消息循环很像,只是多了一个 ref bool handled 参数,对于该参数MSDN是这样说明的: 指示该消息是否已处理的值。如果该消息已处理,请将值设置为 true;否则请将其设置为 false  在下面我们将会使用到这个参数数。
  1. private const int WM_NCHITTEST = 0x0084;  
  2. private readonly int agWidth = 12; //拐角宽度  
  3. private readonly int bThickness = 4; // 边框宽度  
  4. private Point mousePoint = new Point(); //鼠标坐标  
  5.    
  6. protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)  
  7. {  
  8.     switch (msg)  
  9.     {  
  10.         case WM_NCHITTEST:  
  11.         this.mousePoint.X = (lParam.ToInt32() &0xFFFF);  
  12.         this.mousePoint.Y = (lParam.ToInt32() >> 16);  
  13.   
  14.         测试鼠标位置#region 测试鼠标位置  
  15.   
  16.          // 窗口左上角  
  17.          if (this.mousePoint.Y - this.Top <= this.agWidth   
  18.             && this.mousePoint.X - this.Left <= this.agWidth)   
  19.         {  
  20.             handled = true;  
  21.             return new IntPtr((int)HitTest.HTTOPLEFT);  
  22.         }  
  23.         // 窗口左下角      
  24.          else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth   
  25.             && this.mousePoint.X - this.Left <= this.agWidth)  
  26.         {  
  27.             handled = true;  
  28.             return new IntPtr((int)HitTest.HTBOTTOMLEFT);  
  29.         }  
  30.         // 窗口右上角  
  31.          else if (this.mousePoint.Y - this.Top <= this.agWidth   
  32.             && this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth)  
  33.         {  
  34.             handled = true;  
  35.             return new IntPtr((int)HitTest.HTTOPRIGHT);  
  36.         }  
  37.         // 窗口右下角  
  38.          else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth   
  39.             && this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth)  
  40.         {  
  41.             handled = true;  
  42.             return new IntPtr((int)HitTest.HTBOTTOMRIGHT);  
  43.         }  
  44.         // 窗口左侧  
  45.          else if (this.mousePoint.X - this.Left <= this.bThickness)  
  46.         {  
  47.             handled = true;  
  48.             return new IntPtr((int)HitTest.HTLEFT);  
  49.         }  
  50.         // 窗口右侧  
  51.          else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.bThickness)  
  52.         {  
  53.             handled = true;  
  54.             return new IntPtr((int)HitTest.HTRIGHT);  
  55.         }  
  56.         // 窗口上方  
  57.          else if (this.mousePoint.Y - this.Top <= this.bThickness)  
  58.         {  
  59.             handled = true;  
  60.             return new IntPtr((int)HitTest.HTTOP);  
  61.         }  
  62.         // 窗口下方  
  63.          else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.bThickness)  
  64.         {  
  65.             handled = true;  
  66.             return new IntPtr((int)HitTest.HTBOTTOM);  
  67.         }  
  68.         else // 窗口移动  
  69.         {  
  70.             handled = true;  
  71.             return new IntPtr((int)HitTest.HTCAPTION);  
  72.         }  
  73.         #endregion  
  74.     }  
  75.     return IntPtr.Zero;  
  76. }  

     从上面的代码可以看出,工作原理很简单:截取 WM_NCHITTEST 消息,获得鼠标坐标,再在你希望的地方返回不同的消息以模拟鼠标的状态即可。需要注意的是,返回消息之前必须将handled 设为 true。告诉系统你已经处理过该消息,不然无效果。

    关于 HitTest 是自定义的枚举类,里面包含了鼠标的各种消息。

  1. 1public enum HitTest:int  
  2. {  
  3.     HTERROR = -2,  
  4.     HTTRANSPARENT = -1,  
  5.     HTNOWHERE = 0,  
  6.     HTCLIENT = 1,  
  7.     HTCAPTION = 2,  
  8.     HTSYSMENU = 3,  
  9.     HTGROWBOX = 4,  
  10.     HTSIZE = HTGROWBOX,  
  11.     HTMENU = 5,  
  12.     HTHSCROLL = 6,  
  13.     HTVSCROLL = 7,  
  14.     HTMINBUTTON = 8,  
  15.     HTMAXBUTTON = 9,  
  16.     HTLEFT = 10,  
  17.     HTRIGHT = 11,  
  18.     HTTOP = 12,  
  19.     HTTOPLEFT = 13,  
  20.     HTTOPRIGHT = 14,  
  21.     HTBOTTOM = 15,  
  22.     HTBOTTOMLEFT = 16,  
  23.     HTBOTTOMRIGHT = 17,  
  24.     HTBORDER = 18,  
  25.     HTREDUCE = HTMINBUTTON,  
  26.     HTZOOM = HTMAXBUTTON,  
  27.     HTSIZEFIRST = HTLEFT,  
  28.     HTSIZELAST = HTBOTTOMRIGHT,  
  29.     HTOBJECT = 19,  
  30.     HTCLOSE = 20,  
  31.     HTHELP = 21,  
  32. }  
  33.  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 在最大化按钮上。
目录
相关文章
|
C#
WPF 创建无边框的圆角窗口
原文:WPF 创建无边框的圆角窗口 如题所述,在WPF中要创建一个没有边框且为圆角的窗体,有如下几步工作要进行: 第一步:去掉窗体默认样式的边框 首先将窗体的背景设为透明,将允许透明的属性设置为True,...
2701 0
|
编解码 C# 图形学
WPF 窗口大小自适应
原文:WPF 窗口大小自适应 在设置桌面不同分辨率以及较大DPI下,窗口如何显示的问题。 方案一 设置窗口最大值和最小值显示 通过对比当前屏幕的可显示区域,将窗口高宽最大值和最小值,设置为窗口的实际高宽(此例中仅设置高度) 界面设置 设置窗口内容自适应SizeToContent="WidthAndHeight" 添加ViewBox -- 设置默认不拉伸Stretch="None",当DPI超大时如超过1920*1080p的175%(即win10默认不支持的比例显示),开启ViewBox缩放 顶层布局容器RootGrid添加高宽最大值和最小值。
6539 1
|
编解码 前端开发 C#
一起谈.NET技术,利用WPF建立自适应窗口大小布局的WinForm窗口
  编写WinForm程序时,都会碰到一个问题。就是WinForm窗口在不同分辨率下的大小问题。举例说明,你编写的WinForm窗口在1024×768下是合适、匀称的。不过,如果用户的计算机的分辨率为1400×900时,你的WinForm窗口就显得偏小,其中的字体和控件都显得偏小。
1778 0
|
C# Windows
利用WPF创建含多种交互特性的无边框窗体
原文:利用WPF创建含多种交互特性的无边框窗体 咳咳,标题一口气读下来确实有点累,让我先解释一下。另外文章底部有演示程序的下载。
1257 0
|
C#
WPF中制作无边框窗体
原文:WPF中制作无边框窗体 众所周知,在WinForm中,如果要制作一个无边框窗体,可以将窗体的FormBorderStyle属性设置为None来完成。
1532 0
|
API C# Windows
WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例
原文:WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例 键盘钩子是一种可以监控键盘操作的指令。 看到这句话是不是觉得其实键盘钩子可以做很多事情.   场景 当你的程序需要一个全局的快捷键时,可以考虑使用键盘钩子,如大家常用qq的截图快捷键,那么在WPF里怎么去实现呢? 当...
1458 0
|
C#
wpf无边框窗体移动和大小调整
原文:wpf无边框窗体移动和大小调整   using System; using System.Windows; using System.
1646 0
|
C#
WPF,强制捕获鼠标事件,鼠标移出控件外依然可以执行强制捕获的鼠标事件
原文:WPF,强制捕获鼠标事件,鼠标移出控件外依然可以执行强制捕获的鼠标事件 在WPF中,只有鼠标位置在某个控件上的时候才会触发该控件的鼠标事件。例如,有两个控件都注册了MouseDown和MouseUp事件,在控件1上按下鼠标,不要放开,移动到控件2上再放开。
2315 0
|
C#
WPF无边框拖动、全屏、缩放
原文:WPF无边框拖动、全屏、缩放 版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/lwwl12/article/details/78059361 先看效果 无边框 设置WindowStyle=”None”,窗口无关闭及缩放按钮,但还有黑边;设置AllowsTransparency=”True”,黑边没有了。
2099 0
|
C#
WPF一步步实现完全无边框自定义Window(附源码)
原文:WPF一步步实现完全无边框自定义Window(附源码)    在我们设计一个软件的时候,有很多时候我们需要按照美工的设计来重新设计整个版面,这当然包括主窗体,因为WPF为我们提供了强大的模板的特性,这就为我们自定义各种空间提供了可能性,这篇博客主要用来介绍如何自定义自己的Window,在介绍整个写作思路之前,我们来看看最终的效果。
1297 0