为应用程序添加消息过滤器
前几天,在一QQ群上,有一网友提问:如何得到鼠标按下时,点中的是哪个控件。(不能在每个控件的事件中添加 OnMouseDown,因为这样太麻烦,而且控件可能是动态产生的)
当时我的第一反应是:这还不简单,直接重载 Form 的 WndProc 事件就行了
静下来好好想想,才发现自已错在对 WndProc 的理解上, Control.WndProc接收的消息仅仅是发送给该 Control 的,已经被操作系统过滤过的,所以当鼠标点在 TextBox 上时,Form 当然收不到 WM_LBUTTONDOWN 消息.
那假如要实现该功能,要怎么办呢,经查, 用Application.AddMessageFilter 方法可实现,具体代码为:
1.先定义一个消息过滤器
注:msdn 上明确注明,AddMessageFilter 会让系统性能下降,估计其低层是用 SetWindowsHook之类的API.
当时我的第一反应是:这还不简单,直接重载 Form 的 WndProc 事件就行了
const int WM_LBUTTONDOWN = 0x0201;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN)
{
Console.WriteLine(Control.FromHandle(m.HWnd).Name);
}
base.WndProc(ref m);
}
实际运行才发现根本不是那么回事,当我在一个 TextBox 上按下鼠标时,Form的WndProc根本不会执行。protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN)
{
Console.WriteLine(Control.FromHandle(m.HWnd).Name);
}
base.WndProc(ref m);
}
静下来好好想想,才发现自已错在对 WndProc 的理解上, Control.WndProc接收的消息仅仅是发送给该 Control 的,已经被操作系统过滤过的,所以当鼠标点在 TextBox 上时,Form 当然收不到 WM_LBUTTONDOWN 消息.
那假如要实现该功能,要怎么办呢,经查, 用Application.AddMessageFilter 方法可实现,具体代码为:
1.先定义一个消息过滤器
/// <summary>
/// 自定义的消息过滤器,必须实现 IMessageFilter 接口
/// </summary>
class myFilter : IMessageFilter
{
const int WM_LBUTTONDOWN = 0x0201;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN)
{
Console.WriteLine(Control.FromHandle(m.HWnd).Name);
}
return false;
}
}
2.在Form中添加该过滤器/// 自定义的消息过滤器,必须实现 IMessageFilter 接口
/// </summary>
class myFilter : IMessageFilter
{
const int WM_LBUTTONDOWN = 0x0201;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN)
{
Console.WriteLine(Control.FromHandle(m.HWnd).Name);
}
return false;
}
}
private void Form1_Load(object sender, EventArgs e)
{
//为窗体添加消息过滤器
Application.AddMessageFilter(new myFilter());
}
经过这两步后,任何消息都会先发送到 myFilter 中, 用户可处理其中自已感兴趣的消息,OK!{
//为窗体添加消息过滤器
Application.AddMessageFilter(new myFilter());
}
注:msdn 上明确注明,AddMessageFilter 会让系统性能下降,估计其低层是用 SetWindowsHook之类的API.