父控件鼠标进入/离开事件与子控件 [英] Parent Control Mouse Enter/Leave Events With Child Controls

查看:46
本文介绍了父控件鼠标进入/离开事件与子控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 C# .NET 2.0 WinForms 应用程序.我的应用程序有一个控件,它是两个子控件的容器:一个标签和某种编辑控件.你可以这样想,其中外框是父控件:

<前>+---------------------------------+|[标签控件] |+---------------------------------+

当鼠标进入或离开父控件时,我正在尝试做一些事情,但我不在乎鼠标是否移动到它的一个子控件中.我想要一个标志来表示鼠标位于父级或子级内的某处"和鼠标已移出父级控件边界".

我已经尝试在父控件和两个子控件上处理 MouseEnter 和 MouseLeave,但这意味着随着鼠标在控件上移动,操作开始和结束多次.换句话说,我明白了:

<前>Parent.OnMouseEnter(开始做某事)Parent.OnMouseLeave(停止)Child.OnMouseEnter(开始做某事)Child.OnMouseLeave(停止)Parent.OnMouseEnter(开始做某事)Parent.OnMouseLeave(停止)

中间的 OnMouseLeave 事件会导致一些不良影响,因为我正在做的任何事情都会开始然后停止.我想避免这种情况.

我不想在父控件将鼠标悬停时捕获鼠标,因为子控件需要它们的鼠标事件,并且我希望菜单和其他快捷键起作用.

有没有办法在 .NET 框架内做到这一点?还是我需要使用 Windows 鼠标挂钩?

解决方案

经过更多研究,我发现了 Application.AddMessageFilter 方法.使用这个,我创建了一个 .NET 版本的鼠标钩子:

class MouseMessageFilter : IMessageFilter, IDisposable{公共鼠标消息过滤器(){}公共无效处置(){停止过滤();}#region IMessageFilter 成员public bool PreFilterMessage(ref Message m){//调用适当的事件返回假;}#endregion#region 活动公共类 CancelMouseEventArgs : MouseEventArgs{...}公共委托无效CancelMouseEventHandler(对象源,CancelMouseEventArgs e);公共事件 CancelMouseEventHandler MouseMove;公共事件 CancelMouseEventHandler MouseDown;公共事件 CancelMouseEventHandler MouseUp;public void StartFiltering(){停止过滤();Application.AddMessageFilter(this);}公共无效停止过滤(){Application.RemoveMessageFilter(this);}}

然后,我可以在我的容器控件中处理MouseMove事件,检查鼠标是否在我的父控件内,然后开始工作.(我还必须跟踪最后一个鼠标悬停在父控件上的情况,以便我可以停止之前启动的父控件.)

---- 编辑----

在我的表单类中,我创建并连接了过滤器:

public class MyForm : Form{MouseMessageFilter msgFilter;公共 MyForm(){...msgFilter = new MouseMessageFilter();msgFilter.MouseDown += new MouseMessageFilter.CancelMouseEventHandler(msgFilter_MouseDown);msgFilter.MouseMove += new MouseMessageFilter.CancelMouseEventHandler(msgFilter_MouseMove);}私有无效msgFilter_MouseMove(对象源,MouseMessageFilter.CancelMouseEventArgs e){如果 (CheckSomething(e.Control)e.取消=真;}}

I have a C# .NET 2.0 WinForms app. My app has a control that is a container for two child controls: a label, and some kind of edit control. You can think of it like this, where the outer box is the parent control:

+---------------------------------+ 
| [Label Control]  [Edit Control] |
+---------------------------------+

I am trying to do something when the mouse enters or leaves the parent control, but I don't care if the mouse moves into one of its children. I want a single flag to represent "the mouse is somewhere inside the parent or children" and "the mouse has moved outside of the parent control bounds".

I've tried handling MouseEnter and MouseLeave on the parent and both child controls, but this means the action begins and ends multiple times as the mouse moves across the control. In other words, I get this:

Parent.OnMouseEnter      (start doing something)
Parent.OnMouseLeave      (stop)
Child.OnMouseEnter       (start doing something)
Child.OnMouseLeave       (stop)
Parent.OnMouseEnter      (start doing something)
Parent.OnMouseLeave      (stop)

The intermediate OnMouseLeave events cause some undesired effects as whatever I'm doing gets started and then stopped. I want to avoid that.

I don't want to capture the mouse as the parent gets the mouse over, because the child controls need their mouse events, and I want menu and other shortcut keys to work.

Is there a way to do this inside the .NET framework? Or do I need to use a Windows mouse hook?

解决方案

After more research, I discovered the Application.AddMessageFilter method. Using this, I created a .NET version of a mouse hook:

class MouseMessageFilter : IMessageFilter, IDisposable
{
    public MouseMessageFilter()
    {
    }

    public void Dispose()
    {
        StopFiltering();
    }

    #region IMessageFilter Members

    public bool PreFilterMessage(ref Message m)
    {
         // Call the appropriate event
         return false;
    }

    #endregion

    #region Events

    public class CancelMouseEventArgs : MouseEventArgs
    {...}

    public delegate void CancelMouseEventHandler(object source, CancelMouseEventArgs e);
    public event CancelMouseEventHandler MouseMove;
    public event CancelMouseEventHandler MouseDown;
    public event CancelMouseEventHandler MouseUp;

    public void StartFiltering()
    {
        StopFiltering();
        Application.AddMessageFilter(this);
    }

    public void StopFiltering()
    {
        Application.RemoveMessageFilter(this);
    }
}

Then, I can handle the MouseMove event in my container control, check to see if the mouse is inside my parent control, and start the work. (I also had to track the last moused over parent control so I could stop the previously started parent.)

---- Edit ----

In my form class, I create and hookup the filter:

public class MyForm : Form
{
   MouseMessageFilter msgFilter;

   public MyForm()
   {...
       msgFilter = new MouseMessageFilter();
       msgFilter.MouseDown += new MouseMessageFilter.CancelMouseEventHandler(msgFilter_MouseDown);
       msgFilter.MouseMove += new MouseMessageFilter.CancelMouseEventHandler(msgFilter_MouseMove);
    }

    private void msgFilter_MouseMove(object source, MouseMessageFilter.CancelMouseEventArgs e)
    {
        if (CheckSomething(e.Control)
            e.Cancel = true;
    }   
}

这篇关于父控件鼠标进入/离开事件与子控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆