Синхронизация позиций прокрутки для двух DataGrid WPF

StackOverflow https://stackoverflow.com/questions/293275

  •  08-07-2019
  •  | 
  •  

Вопрос

я пытаюсь синхронизировать горизонтальный положение прокрутки из 2 WPF DataGrid элементы управления.

Я подписываюсь на ПрокруткаИзменено событие первого DataGrid:

<toolkit:DataGrid x:Name="SourceGrid" ScrollViewer.ScrollChanged="SourceGrid_ScrollChanged">

У меня есть второй DataGrid:

<toolkit:DataGrid x:Name="TargetGrid">

В обработчике событий я пытался использовать IScrollInfo.SetHorizontalOffset, но, увы, DataGrid не предоставляет IScrollInfo:

private void SourceGrid_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    ((IScrollInfo)TargetGrid).SetHorizontalOffset(e.HorizontalOffset);
    // cast to IScrollInfo fails
}

Есть ли другой способ добиться этого?Или есть ли другой элемент в TargetGrid, который предоставляет необходимые IScrollInfo добиться синхронизации позиций прокрутки?

Кстати, я использование замороженных столбцов, поэтому я не могу обернуть оба элемента управления DataGrid с помощью ScrollViewers.

Это было полезно?

Решение

По мнению группы продуктов Microsoft, обход визуального дерева для поиска ScrollViewer является рекомендуемым методом, так как объяснил в своем ответе на Codeplex .

Другие советы

Для этого есть большой кусок кода:

http://www.codeproject.com/KB/WPF/ScrollSynchronization.aspx

У нас была такая же проблема при использовании сетки Infragistics, потому что она не (по-прежнему не поддерживает) замороженные столбцы. Таким образом, у нас было две сетки рядом, которые были сделаны, чтобы выглядеть как одна. Сетка слева не прокручивалась горизонтально, но сетка справа сделала. Бедный человек замерзшие колонны.

Как бы то ни было, мы в итоге просто полезли в визуальное дерево и сами вытащили ScrollViewer . В конце концов, мы знали, что это было там - это просто не было выставлено объектной моделью. Вы можете использовать аналогичный подход, если сетка WPF не предоставляет ScrollViewer. Или вы можете создать подкласс сетки и добавить функциональность, необходимую для этой работы.

Интересно услышать, зачем вам это нужно.

Вы можете обмануть сетку данных, чтобы представить ее ScrollViewer как открытое свойство для каждой сетки, когда, например, обработчик innerGridControl_ScrollChanged () вызывается во время инициализации usercontrol. Чтобы показать его, вы можете сделать свою сетку в файле xaml View, а затем составить два из них в другом xaml View. Ниже приведен код для innerGrid.xaml.cs, например:

    public ScrollViewer Scroller { get; set; } // exposed ScrollViewer from the grid
    private bool _isFirstTimeLoaded = true; 

    private void innerGridControl_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (_isFirstTimeLoaded) // just to save the code from casting and assignment after 1st time loaded
        {
            var scroller = (e.OriginalSource) as ScrollViewer;
            Scroller = scroller;
            _isFirstTimeLoaded = false;
        }
    }

в OuterGridView.xaml поместите определение обработчика прикрепленного события:

<Views:innerGridView Grid.Row="1" Margin="2,0,2,2" DataContext="{Binding someCollection}" 
                                      x:Name="grid1Control"
                                      ScrollViewer.ScrollChanged="Grid1Attached_ScrollChanged"
                                      ></Views:innerGridView>

<Views:innerGridView Grid.Row="3" Margin="2,0,2,2" DataContext="{Binding someCollection}" 
                                      x:Name="grid2Control"
                                      ScrollViewer.ScrollChanged="Grid2Attached_ScrollChanged"
                                      ></Views:innerGridView>

затем получите доступ к этому общедоступному методу ScrollViewer.SetHorizontOffset (e.Hor horizontalOffset), когда произойдет другое событие прокрутки. Ниже приведен код в OuterGridView.xaml.cs для одного из определений обработчика (

private void Grid1Attached_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (e != null && !e.Handled)
        {
            if (e.HorizontalChange != 0.0)
            {
                grid2Control.Scroller.ScrollToHorizontalOffset(e.HorizontalOffset);
            }
            e.Handled = true;
        }
    }
private void Grid2Attached_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (e != null && !e.Handled)
        {
            if (e.HorizontalChange != 0.0)
            {
                grid1Control.Scroller.ScrollToHorizontalOffset(e.HorizontalOffset);
            }
            e.Handled = true;
        }
    }

Также убедитесь, что для любого другого события scroll_changed во внутренней сетке (если оно есть, например, если вы определяете TextBox со скроллером по умолчанию в одном из шаблонов данных столбца) для e.Handled установлено значение true, чтобы предотвратить обработку обработчиком внешней сетки это (это произошло из-за всплывающего по умолчанию поведения routedevents). В качестве альтернативы вы можете поставить дополнительную проверку, если e.OriginalSource или e.Source отфильтровать событие прокрутки, которое вы собираетесь обрабатывать.

Это отличное решение.У меня отлично работало в WPF.

http://www.codeproject.com/Articles/39244/Scroll-Synchronization

Я только что сделал ссылку на dll ScrollSynchronizer, добавил импорт xml:

xmlns:scroll="clr-namespace:ScrollSynchronizer"

затем просто добавил это как в мои datagrids, так и в bobs вашего дяди:

<DataGrid.Resources>
   <Style TargetType="ScrollViewer">
     <Setter Property="scroll:ScrollSynchronizer.ScrollGroup" Value="Group1" />
   </Style>
</DataGrid.Resources>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top