How do I synchronize two ScrollViewers?
I have four areas. Three of them are scrolled. I need to sync their movement, so if users move area A (horizontal only) area C simulates movement. If the user moves areaC areaA simulates horizontal and areaB vertical movement.
Since some areas can move 'underneath others, I don't see a way to use one ScrollView:
- C moves vertically 'under' A
- C moves horizontally 'under' B
- B moves vertically "under" the fixed area
- A moves horizontally "under" the fixed area
Note that I'm working on a Windows Phone 8.1 app targeting the WinRT runtime (if that current name is missing for it, Silverlight is not.).
About sizes:
- areaA and areaC have the same width
- areaB and areaC have the same height
So far I've managed to keep them in sync by subscribing to events ViewChanging
, reading the offset values NextView
from the arg argument, and calling ScrollTo[Vertical,Horizontal]Offset
on the appropriate other scroller. As I said, it works somehow, but they stutter a little pretty . Plus I haven't found a way to mimic the "end of the scroll", so the content is now compressed up / down.
//adding event handler
areaCScroller.ViewChanging += HandleAreaCScrolls;
//handler
void HandleAreaCScrolls(object sender, ScrollViewerViewChangingEventArgs e)
{
areaAScroller.ScrollToHorizontalOffset(e.NewView.HorizontalOffset);
areaBScroller.ScrollToVerticalOffset(e.NewView.VerticalOffset);
}
I've also tried FinalView values ââ(resulting in StackOverFlowExceptions) and disabling inertia on scrollers (which didn't help, but made them feel less cool).
So my question is, how can I do this better?
I'm not experienced with WPF / XAML, so I could very well miss (or have a low Google foo) control that does what I need. Open to all suggestions (the layout itself is pretty much locked down). I looked here , here and here , but they all do about the same thing that I tried.
source to share
I have used ViewChanged from ScrollViewer. Everything worked well for me. Here is the code from MainPage.xaml.cs:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var list = new List<int>();
for (int i = 0; i < 100; ++i)
{
list.Add(i);
}
ItemsControl1.ItemsSource = list;
ItemsControl2.ItemsSource = list;
}
private void ScrollViewer1_OnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (ScrollViewer1.VerticalOffset != ScrollViewer2.VerticalOffset)
{
ScrollViewer2.ScrollToVerticalOffset(ScrollViewer1.VerticalOffset);
}
}
private void ScrollViewer2_OnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (ScrollViewer1.VerticalOffset != ScrollViewer2.VerticalOffset)
{
ScrollViewer1.ScrollToVerticalOffset(ScrollViewer2.VerticalOffset);
}
}
And the XAML code from MainPage.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0"
x:Name="ScrollViewer1"
ViewChanged="ScrollViewer1_OnViewChanged">
<ItemsControl x:Name="ItemsControl1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ScrollViewer Grid.Column="2"
x:Name="ScrollViewer2"
ViewChanged="ScrollViewer2_OnViewChanged">
<ItemsControl x:Name="ItemsControl2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
Try this, hope it helps.
source to share