Как синхронизировать два ScrollViewers?

У меня есть четыре области. Три из них прокручиваются. Я должен синхронизировать их движение, поэтому, если пользователи перемещают область А (только горизонтальная), область С имитирует движение. Если пользователь перемещает areaC, areaA имитирует горизонтальное, а areaB - вертикальное движение.

Так как некоторые области могут перемещаться "под" другими, я не вижу способа использовать один ScrollView:

  • С движется вертикально "под" А
  • C движется горизонтально "под" B
  • B перемещается вертикально "под" фиксированной областью
  • А движется горизонтально "под" фиксированной областью

4 области

Обратите внимание, что я работаю над приложением Windows Phone 8.1, ориентированным на среду выполнения WinRT (если это текущее название для него? Нет Silverlight, это так).

Что касается размеров:

  • AreaA и AreaC имеют одинаковую ширину
  • areaB и areaC имеют одинаковую высоту

До сих пор мне удавалось синхронизировать их, подписавшись на ViewChanging события, читая NextView значения смещения от события arg и вызова ScrollTo[Vertical,Horizontal]Offset на соответствующем другом скроллере. Как я уже сказал, это работает как-то, но они немного заикаются. Кроме того, я не нашел способа имитировать "достигнут конец прокрутки, поэтому контент теперь сжимается немного вверх / вниз".

//adding event handler
areaCScroller.ViewChanging += HandleAreaCScrolls;

//handler
void HandleAreaCScrolls(object sender, ScrollViewerViewChangingEventArgs e)
{
    areaAScroller.ScrollToHorizontalOffset(e.NewView.HorizontalOffset);
    areaBScroller.ScrollToVerticalOffset(e.NewView.VerticalOffset);
}

Я также попробовал значения FinalView (что привело к StackOverFlowExceptions) и отключил инерцию на скроллерах (что не помогло, но заставило их чувствовать себя менее "круто").

Итак, мой вопрос: как я могу сделать это лучше?

Я не совсем разбираюсь в WPF/XAML, поэтому я вполне могу пропустить (или иметь низкий Google foo) элемент управления или функцию, которая делает то, что мне нужно. Открыто для всех предложений (хотя сам макет в значительной степени заблокирован). Я посмотрел здесь, здесь и здесь, например, но они все делают примерно то же, что я пытался.

1 ответ

Решение

Я использовал ViewChanged из ScrollViewer. У меня все работало нормально. Вот код из 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);
        }
    }

И XAML-код из 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>

Попробуйте это, надеюсь, это поможет.

Другие вопросы по тегам