Синхронизация позиций прокрутки для 2 WPF DataGrids - PullRequest
6 голосов
/ 16 ноября 2008

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

Я подписываюсь на ScrollChanged событие первой 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.

Ответы [ 5 ]

3 голосов
/ 19 ноября 2008

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

2 голосов
/ 03 января 2011

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

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

1 голос
/ 23 января 2014

Вы можете обмануть сетку данных, чтобы представить ее 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 отфильтровать событие прокрутки, которое вы собираетесь обрабатывать.

1 голос
/ 16 ноября 2008

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

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

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

0 голосов
/ 26 июня 2013

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

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

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

xmlns: scroll = "clr-namespace: ScrollSynchronizer"

затем только что добавил это к моим датагридам и покажет вашему дяде:

<DataGrid.Resources>
   <Style TargetType="ScrollViewer">
     <Setter Property="scroll:ScrollSynchronizer.ScrollGroup" Value="Group1" />
   </Style>
</DataGrid.Resources>
...