kartal
kartal

Reputation: 18086

Get row in datagrid

I tried to get row like this :

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

But I only got null. Is there another solution? What am I doing wrong?

I want to get data from my cells. My cells are checkboxes.

Upvotes: 5

Views: 49722

Answers (4)

NG-Designs
NG-Designs

Reputation: 11

Maybe its will be usefull for somebody:

Before add item to DataGrid(WPF), if you want to get non-null DataGridRow in future, to change some properties like Background, you need to create new DataGridRow object, assign your class to DataGridRow.Item property and then add it to DataGrid.

Like this:

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

Upvotes: 1

Hashgrammer
Hashgrammer

Reputation: 155

Getting a DataGrid to take on a suitable data object for manipulation:

Since a DataGrid operates on the principal that it is bound to a data object, you'll want to keep track of your data in something like a DataTable.

For example, initialize a field for your MainWindow class of type DataTable and name it something relevant:

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

Then in your Constructor, after you Initialize the Window component, tie the DataGrid.ItemSource to the DataTable's collection as a data view:

    public MainWindow()
    {
        InitializeComponent();

        dgCars.ItemsSource = _cars.AsDataView();
    }

Now, any time you programmatically add new rows to the _cars table, they will be reflected inside the DataGrid, yay! However, you want to be able to operate on the data from the user interface, so let's dive in!

Operating on the data inside the DataTable, using inputs from the user interface:

When you want to operate on the data, you can get what is selected from the items inside the DataGrid and use the indexes provided by them to remove the items from the DataTable and then re-apply the DataView. That's the summary, but I'll go into more detail and finish the example:

  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
    

Finished product:

This example we've built here allows you to remove data from the DataGrid by selecting rows on it with your mouse and then clicking a button who's Click value equals btnRemove_Click. Simple modifications and logic change will allow you to do the same to add, edit, etc data, but with the principle we originally started with, which is to operate on the data object (in this case, a DataTable) and have that item be the ItemsSource for the DataGrid.

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

-Extra reading-

Earlier in step 4, I mentioned:

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

The reason for this is because _cars and result are both objects instantiated from a class, so they reside on the heap. Items on the heap are garbage collected (removed from memory) when there is no longer a reference to them on the stack. Since _cars is a field of our MainWindow, and continues outside the scope of btnRemove_Click, when we point it to the DataTable result we keep a reference to that table, and drop our reference to the original table. Thus, when btnRemove_Click completes, the variable result is garbage collected, the old DataTable that _cars USED to point to is garbage collected, and _cars now references our new DataTable object that we created.

This answer goes into significantly more detail, and the comments on it are worth reading as well: https://stackoverflow.com/a/80113/13924556

Upvotes: 1

Shahid Ullah
Shahid Ullah

Reputation: 153

  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 is my Grid Name.This code will loop through all records present in Data-grid and Cell/Column Provided.#

Upvotes: -3

Xcalibur37
Xcalibur37

Reputation: 2323

This depends on how / when you are attempting to get this data. WPF is more geared towards accessing the data by the objects bound in the ItemsSource. So, if your ItemsSource is a List of MyObject, then the specific row will be of type MyObject instead of a pure DataRow.

If you are accessing the data by means of clicking on it, you can do something like this:

var currentItem = myDataGrid.SelectedItem as MyObject;

Now, you have the current MyObject in it's originally intended form rather than picking at the grid.

Upvotes: 2

Related Questions