• WPF 下无边框窗体改变大小和移动(转)


     

    WPF 下无边框窗体改变大小和移动(转)

    最近一直在学习 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. }  
     
     
  • 相关阅读:
    ARM板卡ftp客户端应用
    vsftp移植(待续)
    /dev/null脚本中作用
    amazeui.css
    将td中文字过长的部分变成省略号显示的小技巧
    div非弹出框半透明遮罩实现全屏幕遮盖css实现
    重新定位svn地址的方法(windows和linux),svn switch(sw)的帮助信息
    linux 下启动SVN服务
    用SVN checkout源码时,设置账号
    svn提示out of date
  • 原文地址:https://www.cnblogs.com/yanpo/p/2286206.html
Copyright © 2020-2023  润新知