6

我正在尝试同步2 个WPF DataGrid控件的水平滚动位置。

我正在订阅第一个 DataGrid 的ScrollChanged事件:

<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实现滚动位置同步所必需的?

顺便说一句,我使用的是冻结列,所以我不能用 ScrollViewers 包装两个 DataGrid 控件。

4

5 回答 5

3

根据 Microsoft 产品组的说法,遍历可视化树以查找 ScrollViewer 是推荐的方法,正如他们在 Codeplex 上的回答中所解释的那样。

于 2008-11-18T22:54:40.717 回答
3

有一段很棒的代码可以做到这一点:

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

于 2011-01-03T17:38:24.790 回答
1

我们在使用 Infragistics 网格时遇到了同样的问题,因为它(仍然不)支持冻结列。所以我们有两个并排的网格,看起来像一个。左边的网格没有水平滚动,但右边的网格做到了。穷人的冰柱。

无论如何,我们最终只是伸手进入了视觉树并拉出了ScrollViewer我们自己。毕竟,我们知道它就在那里——它只是没有被对象模型暴露出来。如果 WPF 网格不公开 ScrollViewer,您可以使用类似的方法。或者您可以对网格进行子类化并添加您需要的功能来完成这项工作。

有兴趣了解您为什么需要这样做。

于 2008-11-16T10:31:29.267 回答
1

这是一个很好的解决方案。在 WPF 中为我工作得很好。

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

我刚刚引用了 ScrollSynchronizer dll,添加了一个 xml 导入:

xmlns:scroll="clr-命名空间:ScrollSynchronizer"

然后将其添加到我的数据网格和你叔叔的鲍勃:

<DataGrid.Resources>
   <Style TargetType="ScrollViewer">
     <Setter Property="scroll:ScrollSynchronizer.ScrollGroup" Value="Group1" />
   </Style>
</DataGrid.Resources>
于 2013-06-25T22:24:39.740 回答
1

您可以欺骗数据网格将其 ScrollViewer 公开为每个网格的公共属性,例如在用户控件初始化期间调用 innerGridControl_ScrollChanged() 处理程序时。要公开它,您可以在 xaml 视图文件中创建网格,然后在另一个 xaml 视图中组合其中的两个。下面的代码在 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.SetHorizo​​ntalOffset(e.Horizo​​ntalOffset) 方法。下面的代码位于处理程序定义之一的 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 的默认冒泡行为而发生)。或者,您可以添加额外的 if 检查 e.OriginalSource 或 e.Source 以过滤您打算处理的滚动事件。

于 2014-01-23T06:27:31.833 回答