none
Get cell value from WPF Datagrid

    Question

  • I was wondering if there was a simple way of getting the contents (value) of a particular cell in the WPF Datagrid. (In vb.net)
    Say a user clicks on a row. i want to be able to get the value of a cell for that particualr row and for a certain column.
    This was very simple using the datgrid for windows forms but cannot seem to find a way using WPF,.

    Thanks
    Thursday, April 02, 2009 4:05 PM

Answers

  • Hi,

    Please check this helper fuction, thanks to Vincent Sibal.

    public static DataGridCell GetCell(DataGrid dataGrid, int row, int column)
            {
                DataGridRow rowContainer = GetRow(dataGrid, row);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                    // try to get the cell but it may possibly be virtualized
                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    if (cell == null)
                    {
                        // now try to bring into view and retreive the cell
                        dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);

                        cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    }

                    return cell;
                }

                return null;
    }

    After you get the DataGridCell, you might also need to get child visual by VisualTreeHelper class. Please refer to this post:

    http://blogs.msdn.com/vinsibal/archive/2008/11/05/wpf-datagrid-new-item-template-sample.aspx

    Hope this helps.


    Yiling, MVP(Visual C++)
    Friday, April 03, 2009 1:17 AM

All replies

  • Hi,

    Please check this helper fuction, thanks to Vincent Sibal.

    public static DataGridCell GetCell(DataGrid dataGrid, int row, int column)
            {
                DataGridRow rowContainer = GetRow(dataGrid, row);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                    // try to get the cell but it may possibly be virtualized
                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    if (cell == null)
                    {
                        // now try to bring into view and retreive the cell
                        dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);

                        cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    }

                    return cell;
                }

                return null;
    }

    After you get the DataGridCell, you might also need to get child visual by VisualTreeHelper class. Please refer to this post:

    http://blogs.msdn.com/vinsibal/archive/2008/11/05/wpf-datagrid-new-item-template-sample.aspx

    Hope this helps.


    Yiling, MVP(Visual C++)
    Friday, April 03, 2009 1:17 AM
  • Im using DataGrid in WPF,

    when i select an item/cell in my DataGrid, i have to pic that cell's column data....

    for example : if i select a cell(2,3)(row=2 column=3) then i have to collect the column-3 data and present it in a listbox..... THIS IS MY REQUIRMENT

    NOW MY Problem is.....

    1.) How to identify which cell is selected in DataGrid...?

    2.) How to pic dat cell's whole column data ....?

    im frustrated with all those gooogle serch n MSDN help.... so plzzzz help me...




    Beginner in WPF.......VENU
    Saturday, May 16, 2009 12:41 PM
  • I have used ur code given by you........ but i got errors like this....

    Error    1    The type or namespace name 'DataGrid' could not be found (are you missing a using directive or an assembly reference?)
    Error    2    The type or namespace name 'DataGridCell' could not be found (are you missing a using directive or an assembly reference?)

    """"""""""this z ur code"""""""""""""""""""""""""""""""

    Please check this helper fuction, thanks to Vincent Sibal.

    public static DataGridCell GetCell(DataGrid dataGrid, int row, int column)
            {
                DataGridRow rowContainer = GetRow(dataGrid, row);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                    // try to get the cell but it may possibly be virtualized
                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    if (cell == null)
                    {
                        // now try to bring into view and retreive the cell
                        dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);

                        cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    }

                    return cell;
                }

                return null;
    }
    """"""


    plzzz suggest me what i have to do exactly


    Beginner in WPF.......VENU
    Saturday, May 16, 2009 12:46 PM
  • No need to worry stress, the code Yiling Lai gave you is solid and it warks. All you need to do is add the follwing line to your using statement :

    using Microsoft.Windows.Controls.Primitives;

    Make sure you have the write references to your project too. Bu ti am pretty sure the above will do the trick.

    Hope I helped.
    • Proposed as answer by Vvg585 Friday, June 12, 2009 12:28 PM
    Friday, June 12, 2009 12:25 PM
  • Thanks GNS1....

    nway i got the solution...

    I forgot to add the ..."Microsoft.Windows.Controls"--- namespace

    Thank you for ur support.

    Venu

    Beginner in WPF.......VENU
    • Proposed as answer by Vvg585 Friday, June 12, 2009 12:28 PM
    Friday, June 12, 2009 12:28 PM
  • If you want to pick value in currently selected cell

    use

    object item = datagrid.CurrentCell.Item;

    Hope this helps you....
    Wednesday, July 01, 2009 9:46 AM
  • I would like to pick a certain cells value by columns name or index.
    Using the example above it selects the whole row not just a single cells value.
    object item = datagrid.CurrentCell.Item;

    Is there a simple way similar to this that will simply give back the value of a certain cell in the selected row of the wpf datagrid.  It's getting very frustrating not being able to solve this problem.
    Wednesday, December 02, 2009 11:29 AM
  • Its a bit over kill but it does the trick:

        Private Sub Datagrid1_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Datagrid1.MouseDoubleClick
            Dim element As FrameworkElement = TryCast(Datagrid1.InputHitTest(e.GetPosition(Datagrid1)), FrameworkElement)
            If element IsNot Nothing Then
                If TypeOf element.Parent Is DataGridCell Then
    
    
                    Dim dep As DependencyObject = DirectCast(e.OriginalSource, DependencyObject)
    
                    While (dep IsNot Nothing) AndAlso Not (TypeOf dep Is DataGridCell) AndAlso Not (TypeOf dep Is DataGridColumnHeader)
                        dep = VisualTreeHelper.GetParent(dep)
                    End While
    
                    If dep Is Nothing Then
                        Exit Sub
                    End If
    
                    If TypeOf dep Is DataGridColumnHeader Then
                        Dim columnHeader As DataGridColumnHeader = TryCast(dep, DataGridColumnHeader)
    
                        ' find the property that this cell's column is bound to
                        Dim boundPropertyName As String = FindBoundProperty(columnHeader.Column)
    
                        Dim columnIndex As Integer = columnHeader.Column.DisplayIndex
    
                    End If
    
                    If TypeOf dep Is DataGridCell Then
                        Dim cell As DataGridCell = TryCast(dep, DataGridCell)
    
                        ' navigate further up the tree
                        While (dep IsNot Nothing) AndAlso Not (TypeOf dep Is DataGridRow)
                            dep = VisualTreeHelper.GetParent(dep)
                        End While
    
                        If dep Is Nothing Then
                            Exit Sub
                        End If
    
                        Dim row As DataGridRow = TryCast(dep, DataGridRow)
    
                        Dim columnIndex As Integer = cell.Column.DisplayIndex
                        Dim rowIndex As Integer = FindRowIndex(row)
                        getfile(ExtractBoundValue(row, cell, "Document_path").ToString)
    
                        Try
                            yourcellvalue = (ExtractBoundValue(row, cell, "columnheader").ToString)
                        Catch ex As Exception
                            yourcellvalue = "Empty Field"
                        End Try
                                      End If
    
                End If
            End If
        End Sub
    
    
    
            'Determine the index of a DataGridRow
            Private Function FindRowIndex(ByVal row As DataGridRow) As Integer
            Dim dataGrid As DataGrid = TryCast(ItemsControl.ItemsControlFromItemContainer(row), DataGrid)
    
            Dim index As Integer = dataGrid.ItemContainerGenerator.IndexFromContainer(row)
    
            Return index
        End Function
    
            'Find the value that is bound to a DataGridCell
        Private Function ExtractBoundValue(ByVal row As DataGridRow, ByVal cell As DataGridCell, ByVal columnname As String) As Object
            ' find the property that this cell's column is bound to
            Try
                Dim boundPropertyName As String = FindBoundProperty(cell.Column)
    
                ' find the object that is realted to this row
                Dim data As Object = row.Item
    
                ' extract the property value
                Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(data)
                Dim [property] As PropertyDescriptor = properties(columnname)
                Dim value As Object = [property].GetValue(data)
    
                Return value
            Catch ex As Exception
                Return "Empty Field"
            End Try
        End Function
    
            'Find the name of the property which is bound to the given column
           Private Function FindBoundProperty(ByVal col As DataGridColumn) As String
            Dim boundColumn As DataGridBoundColumn = TryCast(col, DataGridBoundColumn)
    
            ' find the property that this column is bound to
            Dim binding As Binding = TryCast(boundColumn.Binding, Binding)
            Dim boundPropertyName As String = binding.Path.Path
    
            Return boundPropertyName
    
        End Function
    I
    Wednesday, December 02, 2009 12:39 PM
  • Ok, different approach from a Itemsource point of view: if all you need is "give back the value of a certain cell in the selected row" then you should know the type of objects that you bind to the datagrid right?

    So if you are binding it to a List of, say customer objects, then you can cast the selected row of the datagrid to a customer object and then extract the value of the cell by accessing the property of the bound object.

    To elaborate, if your customer object has as properties Name, Address and PhoneNumber, and the datagrid is bound to a list (or any other IEnumerable type) of customers, then you can  cast the selected row of the datagrid to a customer object and if you wanna know what value the cell that displays the name has, all you have to do is access the Name property of the object you got from the datagrid.

    Don't know if it  makes any sense that. If not, I can provide a small sample of code or I can try a different approach via accessing the UIElement tree for example.

    Hope it helps.
    Wednesday, December 02, 2009 6:58 PM
  • Ok, different approach from a Itemsource point of view: if all you need is "give back the value of a certain cell in the selected row" then you should know the type of objects that you bind to the datagrid right?

    So if you are binding it to a List of, say customer objects, then you can cast the selected row of the datagrid to a customer object and then extract the value of the cell by accessing the property of the bound object.

    To elaborate, if your customer object has as properties Name, Address and PhoneNumber, and the datagrid is bound to a list (or any other IEnumerable type) of customers, then you can  cast the selected row of the datagrid to a customer object and if you wanna know what value the cell that displays the name has, all you have to do is access the Name property of the object you got from the datagrid.

    Don't know if it  makes any sense that. If not, I can provide a small sample of code or I can try a different approach via accessing the UIElement tree for example.

    Hope it helps.
    It kind of makes sense, but I would be thankful to see a sample code.  This is how I went by binding the data from a LINQ query to the ItemSource:

    // Loading initial data into the DataGrids
                clsLoans objLoans = new clsLoans();
    
                dgUserSearch.ItemsSource = objLoans.GetAllUsers();
    public IQueryable GetAllUsers()
            {
                return from us in myDb.User
                       from usst in myDb.UserStatus
                       where us.UserStatusID == usst.UserStatusID
                       select new
                       {
                           us.UserID,
                           us.UserName,
                           usst.UserStatusDef,
                           us.Address,
                           us.MothersName
                       };
            }

    The above query is part of the clsLoans class, which is on the BusinessLogic layer and it's called from the UserInterface at load time to fill the wpf DataGrid.
    So far so good, but when I try to get the value from the DataGrid it just doesn't work.  I've been looking on forums and trying for more than a day now, but no luck so far.  I can't seem to crack it.
    Do I need to make the query different.  I tried doing some casts so the query would return IQueryable<User> but that can't pass cause I'm gettine values from the User table and UserStatus and that way it doesn't build.

    Mostly the things I did would end up giving me the values of the whole row, but that's not good because I need only a single specific value... that is each value separately so I can assign them to variables (of type string, int etc.) to use them in other places in the code.
    Wednesday, December 02, 2009 8:21 PM
  • Ok, lets try this:
    based on your code i will assume that your datagrid columns are UserID, UserName, UserStatusDef, Address, MothersName.
    You can create a list of objects of type clsLoans: List<clsLoans> = new List<clsLoans>()
    Then you na midify your GetAllusers Method to return a List of clsLoans objects :
    public
     List<clsLoans> GetAllUsers()
    {
    return (from us in myDb.User
    from usst in myDb.UserStatus
    where us.UserStatusID == usst.UserStatusID
    select new
    {
    us.UserID,
    us.UserName,
    usst.UserStatusDef,
    us.Address,
    us.MothersName
    }).ToList();
    }
    and bind your datagrid as you normaly do:
    dgUserSearch.ItemsSource = objLoans.GetAllUsers();

    Then, when say a user clicks a button you can get the sellected item of the datagrid and cast it to type cslLoans:
    cslLoans userSelection=(cslLoans) dgUserSearch.SelectedItem;

    Now you have the sellected item of the datagrid and if you wanna know the value of the cell that contains the UserID all you have to do is:
    userSelection.UserID and you are done.

    Let me know if it helped.

    Thursday, December 03, 2009 12:08 PM

  • Hello GNS1,

    would call you different, but I don't know your real name.
      Your answer was very helpful, but I did ran into some trouble.  I started doing the casting of the query as you said, but since I was getting errors I went on to do the casting directly using the types in my LINQ to SQL class.  So this is what I did to make a list.

    public List<User> GetAllUsers()
            {
                return (from u in myDb.User
                        join us in myDb.UserStatus on u.UserStatusID equals us.UserStatusID
                        select new
                        {
                            u.UserID,
                            u.UserName,
                            us.UserStatusDef,
                            u.Address,
                            u.MothersName
                        }).ToList();
            }
    
    
    This would give the following error message:
    Error: Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<User>'

    So after some trial and error I realized that when I don't do the select new with the specific fields to select then I don't get this error.  Like this:

    public List<User> GetAllUsers()
            {
                return (from u in myDb.User
                        join us in myDb.UserStatus on u.UserStatusID equals us.UserStatusID
                        select u).ToList();
            }
    
    

    With this the code you suggested works like a charm.

    private void dgUserSearch_SelectedCellsChanged(object sender, Microsoft.Windows.Controls.SelectedCellsChangedEventArgs e)
            {
                User userSelection = (User)dgUserSearch.SelectedItem;
                MessageBox.Show(userSelection.UserName);
            }
    
    
    The SelectedCellsChanged event triggers it and there we go the message box, shows the UserName field of the selected row in the datagrid.
    Tho only problem now is that the DataGrid also shows the columns I don't want it to show (some are empty) and some columns like the UserStatusDef it doesn't show.  It shows the UserStatusID since this by what the two tables are related by, but not the UserStatusDef.  I should note tham the AutoGenerateColumns property of the DataGrid is set to true, but I suppose you probably assumed that.  So at the autogeneration I could cancel the generating of the columns I don't want like this:

    private void dgItemSearch_AutoGeneratingColumn(object sender, Microsoft.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)
            {
                switch (e.Column.Header.ToString())
                {
                    case "UserStatusID":
                        e.Cancel;
                        break;
                }//end switch
    
            }//end proc
    
    

    But that would still leave me without the UserStatudDef column which I want to be shown.
    What should I do?


    • Proposed as answer by JRadyn Saturday, May 01, 2010 7:37 AM
    Thursday, December 03, 2009 2:35 PM
  • I'm brand new to working with WPF, and I'm struggling with the same type of problem and came onto this page through my tons of Google searches. I have an idea..

    You basically can create a View in your database, and then the Linq-to-SQL will create the structures you require to read the data from the datagrid in the format you want by following some of the above mentioned code.

    Let me know what you think and whether you have some other solution please.

    Saturday, May 01, 2010 7:42 AM
  • This was given to me after extensive .net research. It sucks in my opinion regardless what the OOPsters are trying to say and make sense of from this nonsense but this does work - don't ask me why - but it does (VB version).

    Dim temprow as datagridrow

    temprow = Me.DataGrid1.ItemContainerGenerator.ContainerFromIndex(5)       'sixth row

    Dim rowview as DataRowView = temprow.item

    Dim cellValue as string = rowview.Item(1).ToString  'second column

    • Proposed as answer by Rajeeshun Tuesday, October 12, 2010 5:29 PM
    Monday, July 12, 2010 3:54 PM
  • Do you konw what the syntax would be to do this in a mouse event in the code behind in C#?

     I should add that I already have a way to get the row and column index numbers, so all I need is the syntax to get the cell value.  Should be simple, I just am very new to working with this structure.

     

     

    Monday, July 19, 2010 4:56 PM
  • OK, so if I understand you right what your are looking for is way to specify your datagrid columns and not rely on Autogenerating. 

    If thats the case then all you have to do is specify the AutoGenerateColumns to false and manualy define the Data grid's columns and provide the binding yourself, like the following example.  Obviously you can set the itemsource of the datagrid as list of your custom objects either in the code-behind or in the XAML. Inside the binding of you datagrid's columns you supply the properrty of the custom object you wish to display and you should be done.

      <dg:DataGrid AutoGenerateColumns="False"/> 
        <dg:DataGrid.Columns>
            <dg:DataGridTextColumn Header="UserName" Binding="{Binding _UserName}" />
            <dg:DataGridTextColumn Header="First Name" Binding="{Binding _Name}" />
            <dg:DataGridTextColumn Header="Last Name" Binding="{Binding _LastName}" />
        </dg:DataGrid.Columns>
        </dg:DataGrid>

    I hope that clarifies it.

    If you still have trouble, define what it is that you wanna do and maybe I can crunk out a sample for you.

    PS: sorry for the possible misformatting of this post but my netbook's battery is going and I am trying to finish the post :)

     

    Wednesday, July 21, 2010 6:30 PM
  • IMHO, that's a terrible misuse of the power of C# and WPF and it should be avoided. I think there are very few cases that you really need to know the cordinates of a cell inside a data grid for a LOB application.

    If your DAL is properly designed and used, and you adhere to the OO principles then that kind of alchemy shouldn't be necessery, but yea, you are right it does work :)

    Regards.

     

     

    • Proposed as answer by Karpedius Monday, August 23, 2010 11:26 AM
    Wednesday, July 21, 2010 6:35 PM
  • This worked well for me.

     

     
     Private Function GetCellValue(ByRef dataGrid As DataGrid, ByVal row As Integer, ByVal column As Integer) As String
        Dim temprow As DataGridRow
        Dim rowview As DataRowView
        Dim cellValue As String
    
        GetCellValue = ""
    
    
        Try
          temprow = dataGrid.ItemContainerGenerator.ContainerFromIndex(row)
          rowview = temprow.Item
          cellValue = rowview.Item(column).ToString 
        Catch ex As Exception
          cellValue = ""
        End Try
    
        Debug.Print(Now & "GetCellValue() = " & cellValue.ToString)
    
        Return cellValue
    
    
      End Function
    
     
    Tuesday, December 21, 2010 2:14 PM
  • @skeltech, How do you get the row and column for your arguments? I am trying to insert a new record in a database and I am trying to check and see if the new record will cause a duplication before I insert.
    Wednesday, February 02, 2011 6:18 PM
  •  Private Sub DataGrid1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles DataGrid1.SelectionChanged
    
      Dim cellText As String
    
      If DataGrid1.SelectedIndex >= 0 Then
    
       cellText = GetCellValue(DataGrid1, DataGrid1.SelectedIndex, DataGrid1.CurrentColumn.DisplayIndex)
    
       Debug.Print(cellText.ToString)
    
      End If
    
     End Sub
    
    

    Thursday, February 17, 2011 4:11 PM
  • I have done this, and it has sort of worked.  For some reason when I display this information in a messagebox I get the fully qualified name: Windows.System.Control DataGridCell <value>.   Can anyone tell me what I need to do using Yilang Lai's code...

     

    Thanks

    Monday, March 14, 2011 12:54 PM
  • ' I basically copied the two methods and fixed a typo. The messagebox and selected cell matched. 
    
    
     Private Sub DataGrid1_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles DataGrid1.MouseDoubleClick
        Dim cellText As String
        If DataGrid1.SelectedIndex >= 0 Then
          cellText = GetCellValue(DataGrid1, DataGrid1.SelectedIndex, DataGrid1.CurrentColumn.DisplayIndex)
          Debug.Print(cellText.ToString)
          MessageBox.Show(cellText.ToString)
        End If
      End Sub
    
    
      Private Function GetCellValue(ByRef dataGrid As DataGrid, ByVal row As Integer, ByVal column As Integer) As String
        Dim temprow As DataGridRow
        Dim rowview As System.Data.DataRowView
        Dim cellValue As String
    
        GetCellValue = ""
    
        Try
          temprow = dataGrid.ItemContainerGenerator.ContainerFromIndex(row)
          rowview = temprow.Item
          cellValue = rowview.Item(column).ToString
        Catch ex As Exception
          cellValue = ""
        End Try
    
        Debug.Print(Now & "GetCellValue() = " & cellValue.ToString)
    
        Return cellValue
    
      End Function
    Friday, March 18, 2011 12:37 PM
  • Suppose I have to get the content value of the current selected cell, then
                 if (myDatagrid.SelectedCells != null && myDatagrid.SelectedCells.Count > 0)
                {
                    DataGridCellInfo dataGridCellInfo = myDatagrid.SelectedCells[0];
                    string propertyName = dataGridCellInfo.Column.Header.ToString();
                    value = GetValue(dataGridCellInfo.Item, propertyName);
                } 
                ....
                ....
              }
              private string GetValue(object item, string propertyName)
             {
                Type t = item.GetType();
                PropertyInfo property = t.GetProperty(propertyName);
                string value = property.GetValue(item, null).ToString();
                return value;
              }
     :)

    Friday, April 01, 2011 9:51 AM
  • Hello,

     

    I am unable get the values updated in the grid. Initially, I am able to populate the grid with data. But on editing any row, I do not get the updated values in the code. Old values are shown in the e.Row.Item .I am using the CellEditEnding() as below.

     

    private void productDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
            {
                if (e.EditAction == DataGridEditAction.Commit)
                {
                    DataGridRow row = e.Row;
                    Product product = (Product)e.Row.Item;

     

    In the product object, old values show up, not the updated ones. Please help..

    Friday, July 15, 2011 1:53 PM
  • All answers are not correct. 

    Please check here[SOLVED]

    http://subrat308.blogspot.in/2012/02/wpf-get-cell-value-from-datagrid-cellij.html

    Saturday, February 11, 2012 7:34 PM
  • Hi ,

    I have another question related same, your solution ll work for CurrentRow or if only one row selected,

    but what happen when i have mutiple row selected then how we can get row index.

    Thanks


    Ashok

    Friday, June 08, 2012 7:24 PM