【发布时间】:2010-10-14 01:58:44
【问题描述】:
我有一个 WPF DataGrid,当屏幕上有太多行无法查看时,它会获得一个垂直滚动条。我想知道的是,当用户滚动时,是否有办法知道顶部可见行是什么。
理想情况下,我希望能够连接一个事件以了解用户何时滚动和滚动,检查顶部可见行以更新一些信息。
【问题讨论】:
我有一个 WPF DataGrid,当屏幕上有太多行无法查看时,它会获得一个垂直滚动条。我想知道的是,当用户滚动时,是否有办法知道顶部可见行是什么。
理想情况下,我希望能够连接一个事件以了解用户何时滚动和滚动,检查顶部可见行以更新一些信息。
【问题讨论】:
订阅 DataGrid 的 ScrollViewer 上的 ScrollViewer.ScrollChanged 事件怎么样?它的事件参数非常广泛,描述了 ScrollViewer 移动了多少以及它的新垂直偏移量是多少。另外,根据 MSDN:
如果 CanContentScroll 为 true,则 ExtentHeight、ScrollableHeight、ViewportHeight 和 VerticalOffset 属性的值是项目数。如果 CanContentScroll 为 false,则这些属性的值是 Device Independent Pixels。
CanContentScroll 确实是 DataGrid 的 ScrollViewer 的情况。
您所要做的就是找到 ScrollViewer:
ScrollViewer scrollview = FindVisualChild<ScrollViewer>(dataGrid);
使用可以在不同地方找到的 FindVisualChild 的实现(例如:Finding control within WPF itemscontrol)。
【讨论】:
使用以下方法对我有用:
// mHorizontalScrollBar is the HorizontalScrollBar subclass control's instance
// Get the total item count
nTotalCount = DataGrid1.Items.Count;
// Get the first visible row index
nFirstVisibleRow = mHorizontalScrollBar.Value;
// Get the last visible row index
nLastVisibleRow = nFirstVisibleRow + nTotalCount - mHorizontalScrollBar.Maximum;
【讨论】:
mHorizontalScrollBar的?
检测滚动很简单
<DataGrid ScrollViewer.ScrollChanged="DataGrid_ScrollChanged" />
现在你必须获得 ScrollViewer 实例:
void DataGrid_ScrollChanged(object sender, RoutedEventArgs e)
{
var scroll = FindVisualChild<ScrollViewer>((DependencyObject)sender);
...
}
(不确定 FindVisualChild 的来源,但有很多实现,例如here)
然后你就可以了
int firstRow = (int)scroll.VerticalOffset;
int lastRow = (int)scroll.VerticalOffset + (int)scroll.ViewportHeight + 1;
【讨论】:
这是一种过于复杂的方法,但它可能会奏效。首先,继承 DataGridRowsPresenter 并覆盖 OnViewportOffsetChanged method。然后,复制数据网格的标准控件模板,并将 DataGridRowsPresenter 替换为您自己的。我将与视口相关的行的命中测试的详细信息留给您;-)。
具体来说,您想要完成什么?也许我们可以想出一个更好的方法,因为这可能非常脆弱并且需要大量额外的工作(即在更新控制模板时保持同步)。
【讨论】:
也许是一个迟到的答案,也许不是最好的方法,而是最简单的方法之一。
public void SelectPatient(string patientID)
{
var item = PatientList.FirstOrDefault(ro => ro.Pati_ID == patientID);
if (item != null)
{
grdPatients.SelectedItem = item;
grdPatients.ScrollIntoView(grdPatients.Items[grdPatients.Items.Count - 1]); //Scrolls to the last row
grdPatients.UpdateLayout();
grdPatients.ScrollIntoView(grdPatients.SelectedItem);
grdPatients.UpdateLayout();
}
}
【讨论】: