在数据网格中获取行

5
我尝试像这样获取行:

我尝试像这样获取行:

DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock cellContent = dataGrid.Columns[0].GetCellContent(row) as TextBlock;

但是我只得到了null。还有其他解决方案吗?我做错了什么吗?

我想从我的单元格中获取数据。我的单元格是复选框。


请查看此解决方案 https://dev59.com/pHI-5IYBdhLWcg3wMFS0#5483614 - Mohammed A. Fadil
4个回答

2
这取决于您尝试获取数据的方式和时间。WPF更适用于通过ItemsSource中绑定的对象访问数据。因此,如果您的ItemsSource是MyObject列表,则特定行将是MyObject类型而不是纯DataRow。
如果您通过单击来访问数据,可以像这样操作:
var currentItem = myDataGrid.SelectedItem as MyObject;

现在,您拥有当前的MyObject,它以最初预期的形式呈现,而不是挑选网格。

1
也许对某些人有用:
在将项目添加到DataGrid(WPF)之前,如果您想在未来获取非空的DataGridRow,并更改像Background这样的某些属性,则需要创建新的DataGridRow对象,将您的类分配给DataGridRow.Item属性,然后将其添加到DataGrid中。
就像这样:
DataGridRow mRow = new DataGridRow();
mRow.Item = YOUR_DATA_CLASS;
_ = datagrid.Items.Add(mRow);

1

DataGrid 接受适当的数据对象以进行操作:

由于 DataGrid 的工作原理是绑定到数据对象,因此您需要将数据保存在类似于 DataTable 的东西中。

例如,为您的 MainWindow 类初始化一个类型为 DataTable 的字段,并给它命名一个相关的名称:

public partial class MainWindow : Window
{
    private DataTable _cars = new DataTable("Cars");

然后在你的构造函数中,在初始化窗口组件之后,将 DataGrid.ItemSource 绑定到 DataTable 的集合作为数据视图:

    public MainWindow()
    {
        InitializeComponent();

        dgCars.ItemsSource = _cars.AsDataView();
    }

现在,无论何时您以编程方式向 _cars 表添加新行,它们都将反映在 DataGrid 中,耶!然而,您希望能够从用户界面操作数据,所以让我们深入探讨一下!

使用用户界面输入操作 DataTable 中的数据:

当您想要操作数据时,您可以获取从 DataGrid 内部选择的项目,并使用它们提供的索引从 DataTable 中删除项目,然后重新应用 DataView。这是摘要,但我会详细介绍并完成示例:

  1. We need to iterate over each DataGrid item and check if it is selected before performing our logic:

        for (int i = 0; i < dgCars.Items.Count; i++)
        {
            if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
            {
                // This is where we do the magic
            }
        }
    
  2. HOWEVER, we can't remove items from the DataTable that is currently being used to supply the DataGrid or we'll run into IndexOutOfBounds (and possibly Enumeration) errors, so to be safe, we'll use a copy of the table to operate on:

        DataTable result = _cars.Copy(); //New in this step
        for (int i = 0; i < dgCars.Items.Count; i++)
        {
            if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
            {
                result.Rows.RemoveAt(i); //New in this step
            }
        }
    
  3. Again, we'll run into IndexOutOfBounds errors, because we are iteration over the data as if there was X amount of data, but each time we RemoveAt(i), we're now iterating over X-- amount of data. So, let's add a count and keep track:

        int removed = 0; //New in this step
        DataTable result = _cars.Copy();
        for (int i = 0; i < dgCars.Items.Count; i++)
        {
            if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
            {
                //Subtracting `removed` new in this step
                result.Rows.RemoveAt(i - removed);
    
                removed++; //New in this step
            }
        }
    
  4. Last, but not least, we'll point our _cars variable to our result DataTable object on the heap and then reassign the dgCars.ItemSource = _cars.AsDataView() to update our DataGrid (a more complicated explanation on this at the very bottom of my answer, if interested):

        int removed = 0;
        DataTable result = _cars.Copy();
        for (int i = 0; i < dgCars.Items.Count; i++)
        {
            if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
            {
                result.Rows.RemoveAt(i - removed);
                removed++;
            }
        }
        _cars = result; //New in this step
        dgCars.ItemSource = _cars.AsDataView(); //New in this step
    

成品:

我们在这里构建的示例允许您通过用鼠标选择行然后单击一个按钮来从DataGrid中删除数据,该按钮的Click值等于btnRemove_Click。简单的修改和逻辑更改将允许您执行相同的操作以添加、编辑等数据,但使用我们最初开始的原则,即操作数据对象(在本例中为DataTable)并使该项成为DataGridItemsSource

public partial class MainWindow : Window
{
    private DataTable _cars = new DataTable("Cars");

    public MainWindow()
    {
        InitializeComponent();

        // THIS WASN'T IN THE BUILD EXAMPLE, BUT AS A BONUS:
        // We could ALSO use this opportunity to setup static
        // column headers if we know what they are in advance!
        _cars.Columns.Add("Year");
        _cars.Columns.Add("Make");
        _cars.Columns.Add("Model");

        dgCars.ItemsSource = _cars.AsDataView();
    }

    private btnRemove_Click(object sender, RoutedEventArgs e)
    {
        int removed = 0;
        DataTable result = _cars.Copy();
        for (int i = 0; i < dgCars.Items.Count; i++)
        {
            if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
            {
                result.Rows.RemoveAt(i - removed);
                removed++;
            }
        }
        _cars = result;
        dgCars.ItemSource = _cars.AsDataView();
    }
}

-额外阅读-

在第四步中,我提到:

最后,我们将把 _cars 变量指向堆上的 result DataTable 对象,然后重新分配 dgCars.ItemSource = _cars.AsDataView() 来更新我们的 DataGrid。

这样做的原因是因为 _carsresult 都是从一个实例化出来的对象,所以它们位于堆上。堆上的项在堆栈上不再有引用时会被垃圾回收(从内存中删除)。由于 _cars 是我们的 MainWindow 的字段,并且继续超出了 btnRemove_Click 的范围,当我们将其指向 DataTable result 时,我们保留了对该表的引用,并且放弃了对原始表的引用。因此,当 btnRemove_Click 完成时,变量 result 被垃圾回收,原来 _cars 指向的旧的 DataTable 被垃圾回收,而 _cars 现在引用我们创建的新 DataTable 对象。

这个答案提供了更详细的信息,它的评论也值得一读:https://dev59.com/hHVD5IYBdhLWcg3wHn2d#80113

-3
  for(int row =0; row < dg_CountInventory.Rows.Count; row ++) //Loop through each row
    {
        //Provide the Column Index and row as in Loop
        TextBlock b = dg_CountInventory.Columns[1].GetCellContent(dg_CountInventory.Items[row ]) as TextBlock; 
    }

dg_CountInventory是我的网格名称。此代码将循环遍历数据网格中提供的所有记录和单元格/列。


7
DataGrid没有Rows属性。 - O. R. Mapper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接