How to show / hide the control on hover

Recently, I have been developing an application, and found myself stuck in a simple but annoying problem.

I would like a particular control to be visible / incomprehensible when I enter its parent element and can execute events (for example: click) of this control. The problem is that mouse hovering doesn’t even work on the parent when entering the control itself that I want to display. This causes the control that I want to display to flicker (mouseover is displayed → control → mouseover no longer works → control is hidden → mouseover works → etc.).

I found this “solution” to help me something “stable”.

// 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); } 

Basically, when I enter an object, a timer starts and is checked every 50 ms if the mouse is in the parent. If so, the control is displayed. If not, the timer stops and the control is hidden.

It works. Hooray. But I find this decision very ugly.

So my question is: is there a different approach, a different solution, more beautiful than this?

Tell me if I'm not clear enough :)

Thanks in advance!

EDIT: Hey, I think I found it myself!

The trick is to override the OnMouseLeave of the parent control with this:

  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); } } 

Thus, when I enter the control that I displayed (by entering the parent control), the mouse stop event does not fire! He works!

Thank you for your responses. You can continue to publish your ideas, I think, because I do not see many solutions on the Internet :)

+4
source share
3 answers

You can make the control transparent to mouse events. In this way, mouse events will pass through it.

You need to write your own class that inherits your desired control. If, for example, Label is your specific control, then create a new class that inherits Label - you get the point. :-)

In your new class, you then use window messages so that your control ignores mouse events:

 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); } } 

You can learn more about WndProc on MSDN .

0
source

You can register a message filter for your form and pre-process the mouse move events of your form. Thanks to this, you do not need to redefine child controls, etc.

The message filter after registration in the parent form will work for child forms, so even if part of your form depends on the shape of your child, your target control should appear / disappear depending on the position of the mouse.

In the following example, the panel has a panel, and the panel has a button inside.

 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; } } } 
0
source

I would do the trick here :) I would wrap the control in a new control :) check this out.

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> 

Code behind:

 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; } 

It is lightweight, lightweight and working. Enjoy

-one
source

All Articles