当前位置: 首页 > news >正文

WPF换肤之三:WPF中的WndProc

原文: WPF换肤之三:WPF中的WndProc

在上篇文章中,我有提到过WndProc中可以处理所有经过窗体的事件,但是没有具体的来说怎么可以处理的。

其实,在WPF中,要想利用WndProc来处理所有的事件,需要利用到SourceInitialized  Event,首先需要创建一个HwndSource对象,然后利用其AddHook方法来将所有的windows消息附加到一个现有的事件中,这个就是WndProc。

 void WSInitialized(object sender, EventArgs e)
        {
            hs = PresentationSource.FromVisual(this) as HwndSource;
            hs.AddHook(new HwndSourceHook(WndProc));
        }

这样,我们就成功地添加了一个可以接收所有windows消息的函数,那么有了它,就让我们用它来做一些有意义的事情吧。

在WPF设计过程中,我是利用一个无边框窗体进行了重绘。所以当我设置其最大化时,肯定是要遮蔽任务栏的:

this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal);

下面就让我们来实现不遮蔽任务栏(参考文章:Maximizing window (with WindowStyle=None) considering Taskbar)。

 

#region 这一部分用于最大化时不遮蔽任务栏
        private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
        {

            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            int MONITOR_DEFAULTTONEAREST = 0x00000002;
            System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {

                MONITORINFO monitorInfo = new MONITORINFO();
                GetMonitorInfo(monitor, monitorInfo);
                RECT rcWorkArea = monitorInfo.rcWork;
                RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
                mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
                mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);
                mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }

        /// <summary>
        /// POINT aka POINTAPI
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            /// <summary>
            /// x coordinate of point.
            /// </summary>
            public int x;
            /// <summary>
            /// y coordinate of point.
            /// </summary>
            public int y;

            /// <summary>
            /// Construct a point of coordinates (x,y).
            /// </summary>
            public POINT(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MINMAXINFO
        {
            public POINT ptReserved;
            public POINT ptMaxSize;
            public POINT ptMaxPosition;
            public POINT ptMinTrackSize;
            public POINT ptMaxTrackSize;
        };
        /// <summary> Win32 </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct RECT
        {
            /// <summary> Win32 </summary>
            public int left;
            /// <summary> Win32 </summary>
            public int top;
            /// <summary> Win32 </summary>
            public int right;
            /// <summary> Win32 </summary>
            public int bottom;

            /// <summary> Win32 </summary>
            public static readonly RECT Empty = new RECT();

            /// <summary> Win32 </summary>
            public int Width
            {
                get { return Math.Abs(right - left); }  // Abs needed for BIDI OS
            }
            /// <summary> Win32 </summary>
            public int Height
            {
                get { return bottom - top; }
            }

            /// <summary> Win32 </summary>
            public RECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }


            /// <summary> Win32 </summary>
            public RECT(RECT rcSrc)
            {
                this.left = rcSrc.left;
                this.top = rcSrc.top;
                this.right = rcSrc.right;
                this.bottom = rcSrc.bottom;
            }

            /// <summary> Win32 </summary>
            public bool IsEmpty
            {
                get
                {
                    // BUGBUG : On Bidi OS (hebrew arabic) left > right
                    return left >= right || top >= bottom;
                }
            }
            /// <summary> Return a user friendly representation of this struct </summary>
            public override string ToString()
            {
                if (this == RECT.Empty) { return "RECT {Empty}"; }
                return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";
            }

            /// <summary> Determine if 2 RECT are equal (deep compare) </summary>
            public override bool Equals(object obj)
            {
                if (!(obj is Rect)) { return false; }
                return (this == (RECT)obj);
            }

            /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary>
            public override int GetHashCode()
            {
                return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();
            }


            /// <summary> Determine if 2 RECT are equal (deep compare)</summary>
            public static bool operator ==(RECT rect1, RECT rect2)
            {
                return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom);
            }

            /// <summary> Determine if 2 RECT are different(deep compare)</summary>
            public static bool operator !=(RECT rect1, RECT rect2)
            {
                return !(rect1 == rect2);
            }
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class MONITORINFO
        {
            /// <summary>
            /// </summary>            
            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

            /// <summary>
            /// </summary>            
            public RECT rcMonitor = new RECT();

            /// <summary>
            /// </summary>            
            public RECT rcWork = new RECT();

            /// <summary>
            /// </summary>            
            public int dwFlags = 0;
        }

        [DllImport("user32")]
        internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

        [DllImport("User32")]
        internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
        #endregion

上面这部分主要就是通过显示器信息来确定窗体显示的WorkArea和MonitorArea。

上面的函数准备好以后,下面就开始处理最大化按钮事件:

首先,让我们来看一个常量:

WM_GETMINMAXINFO

0x24

The   WM_GETMINMAXINFO message is sent to a window when the size or position of the   window is about to change. An application can use this message to override   the window's default maximized size and position, or its default minimum or   maximum tracking size.

从字面意思看来就是这个消息是用来处理窗体大小或者是位置变化的。程序可以使用这个消息来重载原本存在的最大化信息,位置信息等等。

 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case 0x0024:/* WM_GETMINMAXINFO */
                    WmGetMinMaxInfo(hwnd, lParam);
                    handled = true;
                    break;
default: break; } return (System.IntPtr)0; }

上面的代码就是通过处理WM_GETMINMAXINFO消息来实现最大化时不遮蔽任务栏。 我们来看看效果:

需要补充一点的是,在WindowForm中,我们可以通过Point p = new Point(lParam.ToInt32())来确定我们的鼠标坐标在窗体的哪个位置上,但是在WPF中,Point没有带有单个参数的方法,这里只能通过

                    int x = lParam.ToInt32() & 0xffff;
                    int y = lParam.ToInt32() >> 16;

来获取。

希望这篇文章对你有用。

相关文章:

  • 【转】VUE 爬坑之旅-- 如何对公共JS,CSS进行统一管理,全局调用
  • 各个浏览器之间常见的兼容性问题
  • 为什么需要RPC,而不是简单的HTTP接口
  • 和开源硬件相关的几个词,免费、山寨、创客教育,以及未来 | COSCon'18
  • 2018云计算行业现状及2020年云计算发展趋势
  • 当我们谈论Promise时,我们说些什么
  • 谷歌推迟公布Google+漏洞遭参议员不满
  • 今日头条完成超25亿美元融资 软银GA与KKR参与
  • iOS开发中实用的lldb命令
  • 网络时间戳
  • 昨天1024程序员节,我故意写了个死循环~
  • Git常用命令记录
  • Algs4-2.1.32运行时间曲线图
  • BZOJ 3812 : 主旋律
  • 《JavaScript实用效果整理》系列分享专栏
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Netty源码解析1-Buffer
  • python3 使用 asyncio 代替线程
  • Python学习之路13-记分
  • Zepto.js源码学习之二
  • 测试开发系类之接口自动化测试
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 分布式事物理论与实践
  • 构建二叉树进行数值数组的去重及优化
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 微信小程序开发问题汇总
  • 云大使推广中的常见热门问题
  • HanLP分词命名实体提取详解
  • scrapy中间件源码分析及常用中间件大全
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • # 达梦数据库知识点
  • #pragma once与条件编译
  • #数学建模# 线性规划问题的Matlab求解
  • (11)MATLAB PCA+SVM 人脸识别
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (arch)linux 转换文件编码格式
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (Oracle)SQL优化技巧(一):分页查询
  • (poj1.2.1)1970(筛选法模拟)
  • (二)丶RabbitMQ的六大核心
  • (篇九)MySQL常用内置函数
  • (算法二)滑动窗口
  • (未解决)macOS matplotlib 中文是方框
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .form文件_SSM框架文件上传篇
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET MVC第三章、三种传值方式
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .net连接oracle数据库
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...