To support touch operations, we can't disable `HorizontalScrollMode` and `VerticalScrollMode`.
The following seems to work. Can you give it a try?
```xaml
<Grid ColumnDefinitions="*,Auto">
<Grid
Grid.Column="0"
ColumnDefinitions="*,*"
PointerWheelChanged="Grid_PointerWheelChanged"
SizeChanged="Grid_SizeChanged">
<Grid.Resources>
<Style BasedOn="{StaticResource DefaultScrollViewerStyle}" TargetType="ScrollViewer">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalScrollBarVisibility" Value="Hidden" />
<Setter Property="VerticalScrollBarVisibility" Value="Hidden" />
<!--
<Setter Property="HorizontalScrollMode" Value="Disabled" />
<Setter Property="VerticalScrollMode" Value="Disabled" />
-->
</Style>
</Grid.Resources>
<ScrollViewer
x:Name="LeftScrollViewer"
Grid.Column="0"
ViewChanged="LeftScrollViewer_ViewChanged">
<TextBlock FontSize="2048" Text="Left" />
</ScrollViewer>
<ScrollViewer
x:Name="RightScrollViewer"
Grid.Column="1"
ViewChanged="RightScrollViewer_ViewChanged">
<TextBlock FontSize="1024" Text="Right" />
</ScrollViewer>
</Grid>
<ScrollBar
x:Name="VerticalScrollBar"
Grid.Column="1"
IndicatorMode="MouseIndicator"
ValueChanged="VerticalScrollBar_ValueChanged" />
</Grid>
```
```cs
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
VerticalScrollBar.ViewportSize = e.NewSize.Height;
VerticalScrollBar.Maximum = Math.Max(LeftScrollViewer.ScrollableHeight, RightScrollViewer.ScrollableHeight);
}
private void Grid_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
VerticalScrollBar.Value = Math.Max(0, Math.Min(this.VerticalScrollBar.Maximum, this.VerticalScrollBar.Value - e.GetCurrentPoint(this).Properties.MouseWheelDelta));
}
private void VerticalScrollBar_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
if (e.NewValue < 0 || e.NewValue > this.VerticalScrollBar.Maximum)
return;
this.LeftScrollViewer.ScrollToVerticalOffset(e.NewValue);
this.RightScrollViewer.ScrollToVerticalOffset(e.NewValue);
}
private void LeftScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (sender is not ScrollViewer scrollViewer)
return;
VerticalScrollBar.Value = scrollViewer.VerticalOffset;
}
private void RightScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (sender is not ScrollViewer scrollViewer)
return;
VerticalScrollBar.Value = scrollViewer.VerticalOffset;
}
```
I tried your approach using [RenderTransform](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.rendertransform?view=windows-app-sdk-1.7&WT.mc_id=%3Fwt.mc_id%3DMVP_356303) with [TranslateTransform](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.translatetransform?view=windows-app-sdk-1.7&WT.mc_id=%3Fwt.mc_id%3DMVP_356303), but the UI ended up feeling a bit rough. This is what worked better for me:
```xaml
<Grid ColumnDefinitions="*,Auto">
<Grid
Grid.Column="0"
ColumnDefinitions="*,*"
PointerWheelChanged="Grid_PointerWheelChanged"
SizeChanged="Grid_SizeChanged">
<Grid.Resources>
<Style BasedOn="{StaticResource DefaultScrollViewerStyle}" TargetType="ScrollViewer">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalScrollBarVisibility" Value="Hidden" />
<Setter Property="VerticalScrollBarVisibility" Value="Hidden" />
<Setter Property="HorizontalScrollMode" Value="Disabled" />
<Setter Property="VerticalScrollMode" Value="Disabled" />
</Style>
</Grid.Resources>
<ScrollViewer x:Name="LeftScrollViewer" Grid.Column="0">
<TextBlock FontSize="2048" Text="Left" />
</ScrollViewer>
<ScrollViewer x:Name="RightScrollViewer" Grid.Column="1">
<TextBlock FontSize="1024" Text="Right" />
</ScrollViewer>
</Grid>
<ScrollBar x:Name="VerticalScrollBar"
Grid.Column="1"
IndicatorMode="MouseIndicator"
ValueChanged="VerticalScrollBar_ValueChanged" />
</Grid>
```
```cs
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
VerticalScrollBar.ViewportSize = e.NewSize.Height;
VerticalScrollBar.Maximum = Math.Max(LeftScrollViewer.ScrollableHeight, RightScrollViewer.ScrollableHeight);
}
private void Grid_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
VerticalScrollBar.Value = Math.Max(0, Math.Min(this.VerticalScrollBar.Maximum, this.VerticalScrollBar.Value - e.GetCurrentPoint(this).Properties.MouseWheelDelta));
}
private void VerticalScrollBar_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
if (e.NewValue < 0 || e.NewValue > this.VerticalScrollBar.Maximum)
return;
this.LeftScrollViewer.ScrollToVerticalOffset(e.NewValue);
this.RightScrollViewer.ScrollToVerticalOffset(e.NewValue);
}
```