WPF DataGrid:关于可见区域外的所选单元的虚拟化问题

时间:2013-03-15 13:49:49

标签: c# wpf select datagrid virtualization

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

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

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的可见区域内,则此方法非常有效。 因为外面的一切(有几行作为缓冲区)正在虚拟化,但是我遇到了问题。虚拟行并未真正选择,可见区域外的任何单元格都不会随可见区域一起更改其值。

有人可以指导我采用更好的方法吗?是的,我需要处理这些数据,抱歉。 ;)

1 个答案:

答案 0 :(得分:1)

我最近遇到了与WPF数据网格相同的问题。这太慢了。我认为这是因为datagridrow对象对于这么多数据而言太过膨胀。

就我而言,我的处理结果非常相似。我通过完全削减数据网格来解决它。我希望你的#列是不变的,因为如果不是这样的话,实现这种方式会很痛苦(读:我不知道怎么:) :)

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

asInvoker

等...

无论您从何处加载数据,都要遍历数据表/ etc并将列添加到viewmodel中的ObservableCollection对象。

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

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

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;

这样,你可以关闭虚拟化,因为它不像datagrid的对象那么胖,性能要好得多。现在,在没有虚拟化的情况下,您选择的内容确实被选中,并且您可以理智地遍历它。