UWP - PointerEntered/PointerExited 用于模拟网格行上的鼠标悬停

Tir*_*sia 5 c# xaml flicker flyout uwp

我已经检查过在 uwp 中模拟 fontIcon 上的鼠标悬停效果。但我面临着一个不同的“闪烁”问题。

我在 ScrollViewer 中有一个 Grid,它是 PivotItem 控件的子控件。网格一开始是空的,然后以编程方式填充。

<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>
Run Code Online (Sandbox Code Playgroud)

然后每列填充 3 个 TextBlock。我的目标是当鼠标悬停在一行(而不是单个 TextBlock)上时显示带有附加详细信息的浮出控件。为了实现这一点,我为每行定义一个附加的透明矩形,其 ColumnSpan 为 3,并将其添加为每行的最后一个子元素。然后我给它一个弹出窗口,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

这里是 PointerEntered 和 PointerExited 事件处理程序:

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();
}
Run Code Online (Sandbox Code Playgroud)

当指针进入网格行的点击区域时,弹出窗口突然出现并消失。因此,每当指针移动时,即使是在同一行上(我不希望将指针移动到同一行上时,弹出按钮也会消失)。结果是闪烁的弹出窗口。在我看来,PointerEntered/PointerExited 事件都会在悬停的任何点处触发。

我已经尝试过的:

  1. 仅处理 PointerEntered (我知道这不是最佳实践,但我尝试过)
  2. 将 PointerEntered.Handled 设置为 false(我认为网格中的其他控件可能会影响行为)
  3. 仅处理 PointerMoved
  4. 存储“悬停”和“悬停”矩形以识别指针何时位于同一行/另一行上方
  5. 我什至不记得了很多其他尝试......总是得到相同的闪烁结果。

有人能指出我正确的方向吗?先感谢您!

Sun*_* Wu 1

在我看来,PointerEntered/PointerExited 事件都会在悬停的任何点处触发。

似乎一旦Flyout出现,PointerExited即使鼠标没有离开命中测试区域也会触发。如果没有,Flyout事件Pointer可以按照您的想法工作,为此您可以测试官方示例

仅处理 PointerEntered (我知道这不是最佳实践,但我尝试过)

这种方式应该可以工作,因为如果没有PointerExited事件,Flyout就不会被隐藏。我还测试了它Flyout不会消失,直到单击另一个空间。但正如你所说,这可能不是一个好的做法。

 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();
 }
Run Code Online (Sandbox Code Playgroud)

您可以尝试使用另一种方法ToolTip。您甚至不需要Pointer事件,当您将鼠标悬停在该行时,它会显示,而当您移出该行时,它会消失。它不会闪烁。虽然过了一段时间它就会消失,但我认为这足以让你展示细节。

 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);
Run Code Online (Sandbox Code Playgroud)