0

With the following 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>

You can scroll by touching on the TextBlocks. However, if you touch the DataGrid and attempt to scroll, it does nothing.

I'm guessing it has something to do with the fact that the content in the DataGrid is potentially scrollable itself so WPF is getting confused with the potentially nested scrollbars.

The desired behaviour is that touching in the DataGrid will scroll the content inside the DataGrid first (if necessary). Then, when content in the DataGrid has been fully scrolled, the main window will scroll.

James Bateson
  • 1,069
  • 13
  • 20
  • 2
    `DataGrid` has `ScrollViewer` inside, which capture all scroll events for itself. You will have to bubble corresponding events up, see for insight of how it's done for `MouseWheel` and `ListView` [here](http://stackoverflow.com/q/1585462/1997232). – Sinatr Jan 14 '16 at 14:37
  • Thanks @Sinatr. The code indeed works for `PreviewMouseWheel`. However, strangely, it doesn't seem to work for the touch events. I did a similar thing for `PreviewTouchDown`, `PreviewTouchMove` and `PreviewTouchUp` and the top level `ScrollViewer` still does not scroll. – James Bateson Jan 14 '16 at 15:35
  • Actually, if you just slap a Background=Transparent for hittestvisibility on both your scrollviewers it should automatically scroll chaining. I've never had to actually bubble anything anywhere, and it got even easier in the new stuff where you can just toggle scrollchaining via property. – Chris W. Jan 14 '16 at 19:23

2 Answers2

1

Similar to PreviewMouseWheel (Bubbling scroll events from a ListView to its parent), you can do same with Touch controls:

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>

NOTE: This is only for vertical scrolling, but you can add horizontal scrolling in the same way.

neo_st
  • 11
  • 1
1

The solution from @neo_st worked for me. Three important sidenotes to make this work:

  • The Behavior needs to be attached to the outer ScrollViewer.
  • This solution can't handle MultiTouch. If you put two fingers on the touch screen the Events get fired by both fingers and the vertical scroll doesn't work correctly.
  • To get the typical vertical scroll behaviour on the outer ScrollViewer you should change the actualDistance to the original distance as follows:
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;
    }