【问题标题】:WPF DataGrid - How to stay focused on the bottom of the DataGrid as new rows are added?WPF DataGrid - 添加新行时如何保持专注于 DataGrid 的底部?
【发布时间】:2009-08-18 22:31:54
【问题描述】:

我正在使用WPF Toolkit 中的DataGrid,我需要能够将注意力集中在网格的底部(即最后一行)。我现在遇到的问题是,随着添加行,DataGrid 的滚动条不会随着添加的新行一起滚动。完成此任务的最佳方法是什么?

【问题讨论】:

    标签: c# .net wpf datagrid focus


    【解决方案1】:

    看起来DataGrid.ScrollIntoView(<item>) 会将焦点保持在DataGrid 的底部。

    【讨论】:

    • 你在哪里调用这个方法?
    • 确实如此。只需在使用新元素更新数据源后拨打电话即可。请务必在 ScrollIntoView 之前调用 UpdateLayout()!
    • 为什么要先调用UpdateLayout()?我不必那样做。出于某种原因,这只是一种最佳做法吗?
    【解决方案2】:

    这是一个使用 LoadingRow 事件的简单方法:

    void dataGrid_LoadingRow(object sender, System.Windows.Controls.DataGridRowEventArgs e)
    {
        dataGrid.ScrollIntoView(e.Row.Item);
    }
    

    请记住在网格加载完成后禁用它。

    【讨论】:

      【解决方案3】:

      我发现调用ScrollIntoView 方法最有用的时间是来自 ScrollViewer.ScrollChanged 附加事件。这可以在 XAML 中设置如下:

      <DataGrid
      ...
      ScrollViewer.ScrollChanged="control_ScrollChanged">
      

      ScrollChangedEventArgs 对象具有各种有助于计算布局和滚动位置(Extent、Offset、Viewport)的属性。请注意,在使用默认 DataGrid 虚拟化设置时,这些通常以行数/列数来衡量。

      这是一个示例实现,它在将新项目添加到 DataGrid 时保持底部项目处于视图中,除非用户移动滚动条以查看网格中更高的项目。

          private void control_ScrollChanged(object sender, ScrollChangedEventArgs e)
          {
              // If the entire contents fit on the screen, ignore this event
              if (e.ExtentHeight < e.ViewportHeight)
                  return;
      
              // If no items are available to display, ignore this event
              if (this.Items.Count <= 0)
                  return;
      
              // If the ExtentHeight and ViewportHeight haven't changed, ignore this event
              if (e.ExtentHeightChange == 0.0 && e.ViewportHeightChange == 0.0)
                  return;
      
              // If we were close to the bottom when a new item appeared,
              // scroll the new item into view.  We pick a threshold of 5
              // items since issues were seen when resizing the window with
              // smaller threshold values.
              var oldExtentHeight = e.ExtentHeight - e.ExtentHeightChange;
              var oldVerticalOffset = e.VerticalOffset - e.VerticalChange;
              var oldViewportHeight = e.ViewportHeight - e.ViewportHeightChange;
              if (oldVerticalOffset + oldViewportHeight + 5 >= oldExtentHeight)
                  this.ScrollIntoView(this.Items[this.Items.Count - 1]);
          }
      

      【讨论】: