2008-11-16 63 views
6

同步滚动位置我想同步水平滚动位置的2个WPF的DataGrid控件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以实现滚动位置的同步?

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

回答

3

根据Microsoft产品组,遍历视觉树来查找ScrollViewer是推荐方法,如explained in their answer on Codeplex

+0

是的。不过,我过去也是这样做了同样的事情。我们似乎不应该这样通过视觉树来破解。 WPF的另一种方式是粗糙的边缘。 – PeterAllenWebb 2009-05-13 14:32:08

1

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

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

想知道为什么你需要这样做。

+0

我有来自Codeplex的WPF工具包DataGrid的源码,所以我可能能够找到它并公开它(不是我的首选方法)。国王2格获得冻结窗格效果(ala Excel)。 – 2008-11-16 16:16:37

0

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

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

我只是做给ScrollSynchronizer DLL的引用,增加了一个XML导入:

的xmlns:滚动= “CLR的命名空间:ScrollSynchronizer”

然后就将此添加到我的两个数据网格和你的叔叔bobs:

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

你可以欺骗datagrid公开其ScrollViewer作为每个网格的公共属性,何时for示例innerGridControl_ScrollChanged()处理程序在usercontrol的初始化期间调用。 要公开它,您可以在xaml视图文件中创建网格,然后在另一个xaml视图中将它们组成其中的两个。 下面的代码是在innerGrid.xaml.cs例如:在OuterGridView.xaml

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; 
     } 
    } 

把附加的事件处理程序的定义:

<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事件(如果有,例如,如果你定义一个默认的滚动文本框的一个在其中一个列数据模板中)将其e.Handled设置为true以防止外层网格的处理程序处理它(这是由于routedevents的默认冒泡行为发生的)或者,如果检查e.OriginalSource或e.Source以过滤你想要处理的滚动事件