我正在尝试同步 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
以实现滚动位置的同步?
BTW,我使用冻结列,所以我不能用ScrollViewers包装两个DataGrid控件。
答案 0 :(得分:3)
根据Microsoft产品组,浏览可见树以查找ScrollViewer是推荐的方法,explained in their answer on Codeplex。
答案 1 :(得分:2)
答案 2 :(得分:1)
使用Infragistics网格时遇到同样的问题,因为没有(仍然没有)支持冻结列。所以我们有两个并排的网格,看起来像一个。左边的网格不是水平滚动,而是右边的网格。穷人的冷冻柱。
无论如何,我们最终只是伸手进入视觉树并拔出了ScrollViewer
。毕竟,我们知道它就在那里 - 它只是没有被对象模型暴露。如果WPF网格没有公开ScrollViewer,您可以使用类似的方法。或者您可以对网格进行子类化并添加使其工作所需的功能。
有兴趣听听你为什么需要这样做。
答案 3 :(得分:1)
例如,在初始化usercontrol期间调用innerGridControl_ScrollChanged()处理程序时,您可以欺骗datagrid将其ScrollViewer公开为每个网格的公共属性。 要公开它,您可以在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.SetHorizontalOffset(e.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以过滤您要处理的滚动事件,则可以添加其他内容。
答案 4 :(得分:0)
这是一个很好的解决方案。在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>