如何在鼠标悬停事件

时间:2015-07-28 08:55:10

标签: c# winforms

我最近一直在开发一个应用程序,发现自己陷入了一个简单但烦人的问题。

当我输入其父级时,我想使特定控件可见/不可见,并且能够在此控件上执行事件(例如:单击)。问题是,当我输入我想要显示的控件时,鼠标悬停甚至对父节点不起作用。这导致我想要显示的控件闪烁(鼠标悬停工作 - &gt;控件显示 - &gt;鼠标悬停不再起作用 - &gt;控件隐藏 - &gt;鼠标悬停工作 - &gt;等)。< / p>

我找到了这个&#34;解决方案&#34;帮助我找到一些东西&#34;稳定&#34;。

    // Timer to make the control appearing properly.
    private void Timer_Elapsed(object o, ElapsedEventArgs e)
    {
        try
        {
            ItemToHideDisplay.Visible = true;
            var mousePoint = this.PointToClient(Cursor.Position);
            if (mousePoint.X > this.Width ||
                mousePoint.X < 0 ||
                mousePoint.Y > this.Height ||
                mousePoint.Y < 0)
            {
                HideDisplayTimer.Stop();
                ItemToHideDisplay.Visible = false;
                base.OnMouseLeave(e);
            }
        }
        catch
        {
            // We don't want the application to crash...
        }
    }

    protected override void OnMouseEnter(EventArgs e)
    {
        HideDisplayTimer.Start();
        base.OnMouseEnter(e);
    }

基本上,当我输入对象时,如果鼠标在父对象中,则计时器启动并检查每50ms。如果是,则显示控件。如果没有,则停止计时器并隐藏控件。

这很有效。好极了。但我发现这个解决方案非常难看。

所以我的问题是:是否有另一种方法,另一种方法比这种方法更美观?

告诉我,如果我不够清楚:)

提前致谢!

编辑:嘿,我想我自己找到了它!

诀窍是用以下方法覆盖父控件的OnMouseLeave:

    protected override void OnMouseLeave(EventArgs e)
    {
        var mousePoint = this.PointToClient(Cursor.Position);
        if (mousePoint.X > this.Width ||
mousePoint.X < 0 ||
mousePoint.Y > this.Height ||
mousePoint.Y < 0)
        {
            base.OnMouseLeave(e);
        }
    }

这样,当进入我显示的控件(进入父控件)时,不会触发鼠标离开事件! 它有效!

感谢您的回答。你可以继续发表我的想法,因为我在互联网上看不到很多解决方案:)

3 个答案:

答案 0 :(得分:0)

你可以制作一个控制&#34;透明&#34;鼠标事件。所以鼠标事件只会通过它。

你必须编写自己的类继承你想要的控件。例如,如果Label是您的特定控件,那么创建一个继承Label的新类 - 您就明白了。 : - )

在新课程中,您可以使用窗口消息使控件忽略鼠标事件:

protected override void WndProc(ref Message m)
{
    const int WM_NCHITTEST = 0x0084;
    const int HTTRANSPARENT = -1;

    switch(m.Msg)
    {
        case WM_NCHITTEST:
            m.Result = (IntPtr)HTTRANSPARENT;
            break;
        default:
            base.WndProc(ref m);
    }
}

您可以阅读有关WndProc at MSDN的更多信息。

答案 1 :(得分:0)

您可以为表单注册邮件过滤器,并预处理表单的mouse move事件。多亏了这一点,您不必覆盖您的子控件等。

message filter一旦在父表单中注册,也将适用于子表单,因此即使表单的一部分被子表单覆盖,您的目标控件仍应显示/消失,具体取决于鼠标位置。

在以下示例中,表单上有一个面板,该面板内部有一个按钮。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    internal void CaptureMouseMove(Point location)
    {
        if (panel1.RectangleToScreen(panel1.ClientRectangle).Contains(location))
        {
            button1.Visible = true;
            Console.WriteLine(location + "in " + panel1.RectangleToScreen(panel1.ClientRectangle));
        }
        else
        {
            button1.Visible = false;
            Console.WriteLine(location + "out " + panel1.RectangleToScreen(panel1.ClientRectangle));
        }
    }

    internal bool Form1_ProcessMouseMove(Message m)
    {
        Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
        Control ctr = Control.FromHandle(m.HWnd);
        if (ctr != null)
        {
            pos = ctr.PointToScreen(pos);
        }
        else
        {
            pos = this.PointToScreen(pos);
        }
        this.CaptureMouseMove(pos);

        return false;
    }

    private MouseMoveMessageFilter mouseMessageFilter;

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        // add filter here
        this.mouseMessageFilter = new MouseMoveMessageFilter();
        this.mouseMessageFilter.TargetForm = this;
        this.mouseMessageFilter.ProcessMouseMove = this.Form1_ProcessMouseMove;
        Application.AddMessageFilter(this.mouseMessageFilter);
    }

    protected override void OnClosed(EventArgs e)
    {
        // remove filter here
        Application.RemoveMessageFilter(this.mouseMessageFilter);
        base.OnClosed(e);
    }

    private class MouseMoveMessageFilter : IMessageFilter
    {
        public Form TargetForm { get; set; }
        public Func<Message, bool> ProcessMouseMove;

        public bool PreFilterMessage(ref Message m)
        {
            if (TargetForm.IsDisposed) return false;

            //WM_MOUSEMOVE
            if (m.Msg == 0x0200)
            {
                if (ProcessMouseMove != null)
                   return ProcessMouseMove(m);
            }

            return false;
        }
    }
}

答案 2 :(得分:-1)

我会在这里做一个技巧:)我会将控件包装成一个新控件:)检查一下。

XAML:

<UserControl MouseEnter="Border_MouseEnter" MouseLeave="UserControl_MouseLeave" Margin="100" Background="Transparent">
    <UserControl x:Name="ControlToHide" Background="Red">
        <Button Content="hi"  Width="100" Height="100"/>
    </UserControl>
</UserControl>

代码背后:

private void Border_MouseEnter(object sender, MouseEventArgs e)
{
    this.ControlToHide.Visibility = System.Windows.Visibility.Hidden;
}

private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
    this.ControlToHide.Visibility = System.Windows.Visibility.Visible;        
}
它轻巧,简单,有效。享受