【问题标题】:WPF DataGrid: Issue regarding virtualization of selected cells outside of visible areaWPF DataGrid:关于可见区域外选定单元格虚拟化的问题
【发布时间】:2013-03-04 06:29:33
【问题描述】:

我的DataGrid 处理大量数据(平均多达 40k 行),所以我需要进行大量虚拟化。

有时我需要选择某一列中的一大堆(如果不是全部)单元格,以共同更改它们的值。对于任何感兴趣的人,我通过单击列标题(通常对列进行排序)并调用以下方法来实现这一点:

private void SelectColumn(object sender, DataGridSortingEventArgs e)
{
    if (MyDataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
    {
        DataGridColumn column = e.Column;

        if (e.Column != null)
        {
            MyDataGrid.UnselectAllCells();

            for (int i = 0; i < MyDataGrid.Items.Count; i++)
            {
                MyDataGrid.SelectedCells.Add(new DataGridCellInfo(MyDataGrid.Items[i], column));
            }

            // Set the first cell into editing mode
            MyDataGrid.CurrentCell = MyDataGrid.SelectedCells[0];
        }
    }
}

编辑:抱歉,我差点忘了添加设置选定单元格值的代码...:

private void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    if (MyDataGrid.SelectedCells.Count > 1)
    { // More than 1 cell are selected
        if (e.EditingElement.GetType() == typeof(TextBox))
        { // The cell being edited is of type TextBox
            string value = ((TextBox)e.EditingElement).Text;
            foreach (DataGridCellInfo cellInfo in MyDataGrid.SelectedCells)
            {
                DataGridCell gridCell = TryToFindGridCell(MyDataGrid, cellInfo);
                if (gridCell != null) gridCell.Content = value; // ((TextBox)e.EditingElement).Text returns the Text in the cell sending DataGridCellEditEndingEventArgs e
            }
        }
    }
}

static DataGridCell TryToFindGridCell(DataGrid grid, DataGridCellInfo cellInfo)
{
    DataGridCell result = null;
    DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(cellInfo.Item);
    if (row != null)
    {
        int columnIndex = grid.Columns.IndexOf(cellInfo.Column);
        if (columnIndex > -1)
        {
            DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
            result = presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex) as DataGridCell;
        }
    }
    return result;
}

如果所有选定的单元格都在我的 GUI 的可见区域内,这将非常有效。 但是,由于外部的所有内容(有几行作为缓冲区)都被虚拟化,所以我遇到了问题。虚拟化的行并没有真正被选中,可见区域之外的任何单元格都不会与可见的单元格一起改变它们的值。

任何人都可以指导我找到更好的方法吗?是的,我需要处理这么多数据,抱歉。 ;)

【问题讨论】:

  • again。 ;o)
  • 对不起,哈哈。我认为现在关于 SO 上的 WPF DataGrid 的所有问题中有一半是我的。
  • 我不了解虚拟化,但我很确定如果您知道列,您可以连续获取一个单元格。你不能用这种方式得到所有的细胞吗?
  • 这可能不是最好的建议,但如果假设支持网格的数据是可观察的集合。获取编辑值并直接修改可观察集合可能是有意义的。
  • 网格后面的数据是一个DataTable。

标签: c# wpf select datagrid virtualization


【解决方案1】:

我最近在使用 WPF 的数据网格时遇到了同样的问题。这太慢了。我认为这是因为 datagridrow 对象对于这么大的数据量来说太臃肿了。

就我而言,我必须处理的结果数量非常相似。我通过完全取消数据网格来解决它。我希望您的列数保持不变,因为如果不是这种情况,以这种方式实现会很痛苦(阅读:我不确定如何:))......无论如何......

创建一个类并为数据表中的每一列创建一个属性

class TableItem
{
    public string Column1 { get; set: }
    public string Column2 { get; set; }
}

等等……

无论您从何处加载数据,遍历数据表/等并将列添加到视图模型中的 ObservableCollection 对象。

for (int = 0; i < yourDataTable.Rows.Count; i++)
{
    DataRow row = yourDataTable.Rows[i];
    TableItem ti = new TableItem 
    { 
        Column1 = row["Column1Name"].ToString(), 
        Column2 = row["Column2Name"].ToString()
    }
    yourObservableCollection.Add(ti);
}

ObservableCollectionInViewModel = yourObservableCollection;

然后创建一个 ListView,并为其提供所需的列数。将 ListView 绑定到我们刚刚在上面创建的 viewmodel 中的 ObservableCollection,然后使用 DisplayMemberBinding 将每一列绑定到 TableItem 对象的相应属性:

<ListView x:Name="lstGridWOResourceHogging" SelectionMode="Extended" ItemsSource="{Binding ObservableCollecitonInViewModel, IsAsync="True"
              VirtualizingPanel.IsVirtualizing="False">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Column1Name" DisplayMemberBinding="{Binding Column1}"/>
                <GridViewColumn Header="Column2Name" DisplayMemberBinding="{Binding Column2}"/>
            </GridView>
        </ListView.View>
    </ListView>

这样,您可以关闭虚拟化,因为它不像数据网格的对象那么胖,所以性能要好得多。现在,在没有虚拟化的情况下,您真正​​选择的内容已被选中,您可以理智地迭代它。

【讨论】:

  • 只是为了更新,ListView 更快,但仍然不是“快”。 WPF 的对象/依赖属性不可避免地会占用过多的内存,例如当您需要数千个对象(数据行)时。如果您真的需要快速,Windows Forms Host 将有助于将 Windows Forms DataGridView 放入 WPF 应用程序中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
  • 2019-12-01
  • 1970-01-01
相关资源
最近更新 更多