C# WPF OnMouseEnter and OnMouseLeave loops

Viewed 269

I have WPF UI Elements that should be hidden when mouse cursor enter in this elements and be visible when mouse cursor leave from this elements. For this things i using events OnMouseEnter & OnMouseLeave, like this:

private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
    (e.Source as UIElement).Visibility = Visibility.Hidden;
}

private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
{
    (e.Source as UIElement).Visibility = Visibility.Visible;
}

(code below from https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.panel.zindex?view=netframework-4.8)

<Canvas>
            <Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="100" Canvas.Left="100" Fill="blue" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>
            <Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="150" Canvas.Left="150" Fill="yellow" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>
            <Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="200" Canvas.Left="200" Fill="green" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>

            <!-- Reverse the order to illustrate z-index property -->

            <Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="300" Canvas.Left="200" Fill="green" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>
            <Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="350" Canvas.Left="150" Fill="yellow" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>
            <Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="400" Canvas.Left="100" Fill="blue" MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"/>
        </Canvas>

But when i run program and hover cursor on the element, it starts to flicker and eat up quite a lot of CPU resources.

Debugging shows that when i hover cursor on element, events loops until I move the cursor off the element.

I saw this article, but I don't understand the solution that is attached there.

What do I need to do to prevent these events from looping?

2 Answers

When you change the Visibility of a UIElement to Hidden, you are actually triggering a MouseLeave event because the mouse hit test is now performed on the element behind it. And that runs your event handler, which sets the Visibility to Visible which then triggers the MouseEnter event. Hence the flicker.

One idea to solve this is to use Opacity instead of Visibility. Try:

private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
  (e.Source as UIElement).Opacity = 0;
}

private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
{
  (e.Source as UIElement).Opacity = 1;
}

You are likely causing a "paint event" by repeatedly setting the same value, try this and see if you are happy

private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
   if(e.Source is UIElement element && element.Visibility != Visibility.Hidden )
   {
     element.Visibility = Visibility.Hidden;
   }   
}
Related