5

I have already checked Simulating a mousehover effect on a fontIcon in uwp. But I am facing a different, "flickering" issue.

I have a Grid inside a ScrollViewer, which is a child of a PivotItem control. The grid is empty at the beginning and then programmatically populated.

<PivotItem>
    <ScrollViewer x:Name="MyScrollBar" >
        <Grid Name="MyGrid">
            <Grid.RowDefinitions>
                 <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="*"></ColumnDefinition>
                 <ColumnDefinition Width="*"></ColumnDefinition>
                 <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
         </Grid> 
    </ScrollViewer>
</PivotItem>

The columns are then filled with 3 TextBlocks each. My goal is to show a Flyout with additional details when hovering over a row (not a single TextBlock). To achieve this, I define for each row an additional transparent Rectangle whose ColumnSpan is 3, and add it as the last child of each row. I then give it a Flyout as follows:

Rectangle rect = new Rectangle();
rect.Opacity = 0;
rect.SetValue(Grid.RowProperty, r);
rect.SetValue(Grid.ColumnSpanProperty, 3);
Flyout fl = new Flyout();
Grid flGrid = new Grid();
TextBlock flTb1 = new TextBlock();
flTb1.Text = details.Name;
flGrid.Children.Add(flTb1);
fl.Content = flGrid;
rect.SetValue(FlyoutBase.AttachedFlyoutProperty, fl);
rect.PointerEntered += Rect_PointerEntered;
rect.PointerExited += Rect_PointerExited;
rect.Margin = new Thickness(2);

Here the PointerEntered and PointerExited event handlers:

private void Rect_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    ((Flyout)(((Rectangle)sender).GetValue(FlyoutBase.AttachedFlyoutProperty))).ShowAt((Rectangle)sender);
}

private void Rect_PointerExited(object sender, PointerRoutedEventArgs e)
{
    ((Flyout)(((Rectangle)sender).GetValue(FlyoutBase.AttachedFlyoutProperty))).Hide();
}

As the pointer enters the hit zone of a grid row, suddenly the Flyout appears and disappears. And so it does whenever the pointer moves, even over the same row (I don't want the Flyout to disappear when moving the pointer over the same row). The result is a flickering flyout. It seemes to me that the PointerEntered/PointerExited events are both fired at any point hovered.

What I have already tried:

  1. Handle the PointerEntered only (I know this is not best practice, but I tried)
  2. Set PointerEntered.Handled to false (I thought that maybe the other controls in the grid were impacting the behavior)
  3. Handle the PointerMoved only
  4. Stored the "hovered" and "hovering" Rectangle(s) to recognize when the pointer is above the same/another row
  5. A lot of other attempts I don't even remember... always getting the same flickering results.

Could anyone point me in the right direction? Thank you in advance!

Community
  • 1
  • 1
Tiresia
  • 91
  • 8

3 Answers3

1

It seemes to me that the PointerEntered/PointerExited events are both fired at any point hovered.

It seems like once the Flyout appears the PointerExited will triggered even the mouse didn't leave the hit test area. Without the Flyout the Pointer events can work as you thought about, for this you can test the official sample.

Handle the PointerEntered only (I know this is not best practice, but I tried)

This way should be able worked since without PointerExited event the Flyout will not be hidden. I also tested it the Flyout will not disappear until click on another space. But as you said this may not be a good practice.

 private void Rect_PointerEntered(object sender, PointerRoutedEventArgs e)
 {
    ((Flyout)(((Rectangle)sender).GetValue(FlyoutBase.AttachedFlyoutProperty))).ShowAt((Rectangle)sender);
 }

 private void Rect_PointerExited(object sender, PointerRoutedEventArgs e)
 {
     //((Flyout)(((Rectangle)sender).GetValue(FlyoutBase.AttachedFlyoutProperty))).Hide();
 }

A another way you can try to use ToolTip. You even don't need Pointer events, when you hovering the row, it will show, and when you move out it will disappear. It will not be flickering. Although after a time it will disappear but I think it is enough for you showing details.

 Rectangle rect = new Rectangle();
 rect.Opacity = 0.3;
 rect.SetValue(Grid.RowProperty, r);
 rect.SetValue(Grid.ColumnSpanProperty, 3);
 rect.Fill = new SolidColorBrush(Colors.Azure);  
 Grid flGrid = new Grid();
 TextBlock flTb1 = new TextBlock();
 flTb1.Text = "testname"+r;
 flGrid.Children.Add(flTb1); 
 rect.SetValue(ToolTipService.ToolTipProperty, flGrid); 
 rect.Margin = new Thickness(2);
 MyGrid.Children.Add(rect);
Sunteen Wu
  • 10,509
  • 1
  • 10
  • 21
  • The problem with the tooltips is that you cannot put interactive controls such as buttons or sliders inside a tooltips. While it's work great with the pointer in and existed behavior, interactive controls will cause the app to cash after you try to touch it. – Boommer Mar 29 '21 at 08:02
1

As @Sunteen has pointed out in a previous answer, the flyout will activate a PointerExited event. You could use a TeachingTip control instead of a flyout. The TeachingTip control doesn't trigger a PointerExited so you can get the hover-over effect. Note you may need to add the TeachingTip control. See Implementing TeachingTip control for a UWP App

<xmlns:controls="using:Microsoft.UI.Xaml.Controls">
<Image 
    Name="draggable_image"  
    PointerEntered="Draggable_image_PointerEntered"
    PointerExited="Draggable_image_PointerExited"/>       
<controls:TeachingTip 
    x:Name="IconTip"
    Target="{x:Bind draggable_image}"
    PreferredPlacement="Bottom"
    PlacementMargin="10"/>

 private void Draggable_image_PointerEntered(object sender, PointerRoutedEventArgs e) 
 {
     //IconTip.Title = set title 
     //IconTip.Subtitle = set sub title;
     IconTip.IsOpen = true;

 }

 private void Draggable_image_PointerExited(object sender, PointerRoutedEventArgs e)
 {
     IconTip.IsOpen = false;
 }
Jason Pratt
  • 121
  • 4
0

For anyone that happens to stumble across this issue 6 years after it was posted. Try OverlayInputPassthroughElement

Prevented the creation of the flyout from consuming the pointer and firing a PointerExited event.

Documentation

  • Tried used it to point to the element that use PointerExited but PointerExited still firing. – Nick Mar 31 '23 at 01:17