I'm trying to create a touchscreen interface similar to the macOS Finder's column view, which is a series of horizontally-stacked lists where each list is individually scrollable (vertically) and the whole thing is scrollable horizontally, like this:
Here is my .NET 4.6.1 "minimum viable code sample" to demonstrate what I'm doing:
Front end:
<Window x:Class="TestNestedScroll.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestNestedScroll"
Title="MainWindow" Height="500" Width="800"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" PanningMode="HorizontalOnly">
<ItemsControl ItemsSource="{Binding Columns}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" PanningMode="VerticalOnly">
<ItemsControl ItemsSource="{Binding Rows}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="300" Height="100" Fill="Purple" Margin="20"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Window>
Back end:
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace TestNestedScroll
{
public partial class MainWindow : Window
{
public class Row {}
public class Column { public List<Row> Rows { get; } = Enumerable.Repeat( new Row(), 20 ).ToList(); }
public List<Column> Columns { get; } = Enumerable.Repeat( new Column(), 10 ).ToList();
public MainWindow()
{
InitializeComponent();
}
}
}
Right now I can only get this to work one way -- either I turn off PanningMode
on the inner scroll viewers and I can scroll the outer ScrollViewer
left and right, or I set PanningMode="VerticalOnly"
(or Both
, or VerticalFirst
, doesn't matter) on the inner scroll viewers and they become individually vertically scrollable, but the horizontal ScrollViewer
stops working.
Is there a way to make this work? Perhaps the horizontal touch events on the inner ScrollViewers
have to be caught and manually bubbled up to the parent ScrollViewer
somehow -- how would I do that?