WPF - ScrollViewer 元素内的内容在触摸子 DataGrid 时不会触摸滚动



使用以下 XAML:

<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="600" Width="640">
<ScrollViewer PanningMode="Both">
    <StackPanel>
        <TextBlock TextWrapping="Wrap">LOTS OF TEXT...</TextBlock>
        <DataGrid MinHeight="200">
                <DataGrid.Columns>
                    <DataGridTextColumn Width="100"></DataGridTextColumn>
                    <DataGridTextColumn Width="100"></DataGridTextColumn>
                    <DataGridTextColumn Width="100"></DataGridTextColumn>
                </DataGrid.Columns>
            </DataGrid>
        <TextBlock TextWrapping="Wrap">LOTS OF TEXT...</TextBlock>
    </StackPanel>
</ScrollViewer>
</Window>

您可以通过触摸TextBlock s来滚动。 但是,如果您触摸DataGrid并尝试滚动,则它不会执行任何操作。

我猜这与DataGrid中的内容本身可能是可滚动的这一事实有关,因此 WPF 与潜在的嵌套滚动条混淆。

所需的行为是,触摸DataGrid将首先滚动DataGrid内的内容(如有必要)。 然后,当DataGrid中的内容完全滚动时,主窗口将滚动。

与 PreviewMouseWheel(冒泡滚动事件从 ListView 到其父级)类似,您可以使用触摸控件执行相同的操作:

C#:

public sealed class SubControlsTouchScrollEvent : Behavior<UIElement>
{
    double originalDistance;
    double actualDistance;
    int delta;
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTouchDown += AssociatedObject_PreviewTouchDown;
        AssociatedObject.PreviewTouchMove += AssociatedObject_PreviewTouchMove;
    }
    protected override void OnDetaching()
    {
        AssociatedObject.PreviewTouchUp -= AssociatedObject_PreviewTouchDown;
        AssociatedObject.PreviewTouchMove -= AssociatedObject_PreviewTouchMove;
        base.OnDetaching();
    }
    void AssociatedObject_PreviewTouchDown(object sender, TouchEventArgs e)
    {
        System.Windows.IInputElement s = sender as System.Windows.IInputElement;
        originalDistance = e.GetTouchPoint(s).Position.Y;
    }
    void AssociatedObject_PreviewTouchMove(object sender, TouchEventArgs e)
    {
        ScrollViewer s = sender as ScrollViewer;
        actualDistance = e.GetTouchPoint(s).Position.Y;
        delta = Convert.ToInt16(actualDistance - originalDistance);          
        s.ScrollToVerticalOffset(s.VerticalOffset - (delta * 0.1));
        e.Handled = true;
    }
}

XAML:

<ScrollViewer PanningMode="Both" Background="Transparent">
   <interactivity:Interaction.Behaviors>
      <local:SubControlsTouchScrollEvent />
   </interactivity:Interaction.Behaviors>
</ScrollViewer>

注意:这仅适用于垂直滚动,但您可以以相同的方式添加水平滚动。

@neo_st的解决方案对我有用。完成这项工作的三个重要旁注:

  • 行为需要附加到外部滚动查看器
  • 此解决方案无法处理多点触控。如果您将两根手指放在触摸屏上,则事件会被两根手指触发,垂直滚动无法正常工作。
  • 要在外部滚动查看器上获得典型的垂直滚动行为,您应该将实际距离更改为原始距离,如下所示:
void AssociatedObject_PreviewTouchMove(object sender, TouchEventArgs e)
    {
        ScrollViewer s = sender as ScrollViewer;
        
        actualDistance = e.GetTouchPoint(s).Position.Y;
        delta = Convert.ToInt16(actualDistance - originalDistance);   
        
        s.ScrollToVerticalOffset(s.VerticalOffset - delta);
        originalDistance = actualDistance;
        
        e.Handled = true;
    }

最新更新