【问题标题】:Get row in datagrid获取数据网格中的行
【发布时间】:2011-12-11 14:29:12
【问题描述】:

我试图得到这样的行:

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

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

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

【问题讨论】:

标签: c# wpf datagrid row


【解决方案1】:

这取决于您尝试获取此数据的方式/时间。 WPF 更适合通过 ItemsSource 中绑定的对象访问数据。因此,如果您的 ItemsSource 是 MyObject 的 List,那么特定行将是 MyObject 类型,而不是纯 DataRow。

如果您通过点击来访问数据,您可以执行以下操作:

var currentItem = myDataGrid.SelectedItem as MyObject;

现在,您已经将当前的 MyObject 保持在其最初预期的形式中,而不是在网格上进行选择。

【讨论】:

    【解决方案2】:

    获取DataGrid 以获取合适的数据对象进行操作:

    由于DataGrid 对绑定到数据对象的主体进行操作,因此您需要以DataTable 之类的方式跟踪数据。

    例如,为 DataTable 类型的 MainWindow 类初始化一个字段并将其命名为相关:

    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里面的item中获取选择的内容,并使用它们提供的索引从DataTable中移除item,然后重新应用DataView。这就是摘要,但我将更详细地完成示例:

    1. 在执行我们的逻辑之前,我们需要遍历每个 DataGrid 项目并检查它是否被选中:

          for (int i = 0; i < dgCars.Items.Count; i++)
          {
              if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
              {
                  // This is where we do the magic
              }
          }
      
    2. 但是,我们无法从当前用于提供 DataGridDataTable 中删除项目,否则我们将遇到 IndexOutOfBounds(可能还有 Enumeration)错误,因此为了安全起见,我们将使用要操作的表的副本:

          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. 再一次,我们会遇到 IndexOutOfBounds 错误,因为我们正在迭代数据,就好像有 X 的数据量一样,但是每次我们 RemoveAt(i) 时,我们现在都在迭代 X-- 的数量数据的。所以,让我们添加一个计数并跟踪:

          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. 最后但并非最不重要的一点是,我们将_cars 变量指向堆上的result DataTable 对象,然后重新分配dgCars.ItemSource = _cars.AsDataView() 以更新我们的DataGrid (对此有更复杂的解释,请参阅我的答案的最底部,如果有兴趣)

          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)进行操作并拥有项目是ItemsSourceDataGrid

    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();
        }
    }
    

    -补充阅读-

    在前面的第 4 步中,我提到过:

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

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

    这个答案要详细得多,上面的 cmets 也值得一读:https://stackoverflow.com/a/80113/13924556

    【讨论】:

      【解决方案3】:

      也许它对某人有用:

      在将项目添加到 DataGrid(WPF) 之前,如果您想在将来获得非空 DataGridRow,要更改背景等一些属性,您需要创建新的 DataGridRow 对象,将您的类分配给 DataGridRow.Item 属性,然后添加它到 DataGrid。

      像这样:

      DataGridRow mRow = new DataGridRow();
      mRow.Item = YOUR_DATA_CLASS;
      _ = datagrid.Items.Add(mRow);
      

      【讨论】:

        【解决方案4】:
          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 是我的网格名称。此代码将遍历所有记录 存在于提供的数据网格和单元格/列中。#

        【讨论】:

        猜你喜欢
        • 2012-09-27
        • 2014-12-24
        • 2018-03-03
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多