none
Reading a cell value in a WPF DataGrid?

    Question

  • I need to get the text value from a DataGrid cell when the user clicks on a row (I need the value of the first cell in the row).  I just can't figure out how to get the value of that one cell. If I try the "GotMouseCapture" event:

    string text = myDataGrid.SelectedValue.ToString();

    I get the contents of the entire row (setting the selection unit on the grid to "cell" gives me a Null Reference Exception). I get the same exception when using 

                DataGridCell cell = sender as DataGridCell;  
                if (cell.IsSelected) {  
                    tbItem1.Text = cell.Content.ToString();  
                }  
     

    I'm new to the WPF DataGrid, and it's fairly frustrating, especially when compared to the DataGridView from WinForms, but I want to learn how to use it, as the DataBinding it provides is real nice.

    Any ideas?
    Thanks!

    Thursday, December 4, 2008 5:27 PM

Answers

  • You're missing the key feature from WPF data processing. You're not actually accessing items in a grid like rows and columns in an Excel sheet. You should think of it as accessing objects in an ObservableCollection<T> and its properties.

    Say you have a class like this:

    public class Person 
      public string FirstName {get;set;} 
      public string LastName {get;set;} 


    And you populate your grid like so:

    grid.ItemSource = new ObservableCollection<Person> { 
      new Person { FirstName = "John", LastName = "Doe" }, 
      new Person { FirstName = "Jane", LastName = "Eod" } 


    Instead of accessing a first column you access the property. Something like so:
    var person = grid.SelectedItem as Person; 
    if (person != null) textBlock.Text = person.FirstName; 


    Bigsby, Lisboa, Portugal
    • Marked as answer by pedro45acp Friday, December 5, 2008 5:24 PM
    Thursday, December 4, 2008 5:45 PM

All replies

  • You're missing the key feature from WPF data processing. You're not actually accessing items in a grid like rows and columns in an Excel sheet. You should think of it as accessing objects in an ObservableCollection<T> and its properties.

    Say you have a class like this:

    public class Person 
      public string FirstName {get;set;} 
      public string LastName {get;set;} 


    And you populate your grid like so:

    grid.ItemSource = new ObservableCollection<Person> { 
      new Person { FirstName = "John", LastName = "Doe" }, 
      new Person { FirstName = "Jane", LastName = "Eod" } 


    Instead of accessing a first column you access the property. Something like so:
    var person = grid.SelectedItem as Person; 
    if (person != null) textBlock.Text = person.FirstName; 


    Bigsby, Lisboa, Portugal
    • Marked as answer by pedro45acp Friday, December 5, 2008 5:24 PM
    Thursday, December 4, 2008 5:45 PM
  • Thank you! That certainly pointed my in the direction and helped me understand the issue a lot better.
    Friday, December 5, 2008 5:25 PM
  • can you please help me on this

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/25741021-94e1-44aa-a186-ed4af57e402a

    Many Thanks Deepak
    Sunday, April 26, 2009 12:19 PM
  • You're missing the key feature from WPF data processing. You're not actually accessing items in a grid like rows and columns in an Excel sheet. You should think of it as accessing objects in an ObservableCollection<T> and its properties.

    Say you have a class like this:

    public   class  Person 
      public   string  FirstName { get ; set ;} 
      public   string  LastName { get ; set ;} 


    And you populate your grid like so:

    grid.ItemSource =  new  ObservableCollection<Person> { 
      new  Person { FirstName =  "John" , LastName =  "Doe"  }, 
      new  Person { FirstName =  "Jane" , LastName =  "Eod"  } 


    Instead of accessing a first column you access the property. Something like so:
    var  person  =  grid .SelectedItem as Person; 
    if (person != null) textBlock.Text  =  person .FirstName; 


    Bigsby, Lisboa, Portugal
    That seems as a good solution to the problem, but how do I do this if I'm making a three layer application. Layer:
    1.  DataAcces (this has the Linq to Sql class)
    2.  BusinessLogic (has classes to tables, linq queries etc.)
    3.  User Interface (UI)

    So I have the DataGrid on the UI and it's populated like this:

    // Loading initial data into the DataGrids
                clsLoans objLoans = new clsLoans();
    
                dgUserSearch.ItemsSource = objLoans.GetAllUsers();
    The GetAllUsers() function is called from the BL and is in a class called clsLoans, and returns an IQueriable LINQ query.

    public SmalLibData myDb = new SmalLibData(ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString);

    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 };
    }
    I also have a class in the BL for each table with the functions and queries related to it.  For example the class for the User table (clsUser) looks like this:

    public class clsUserBL
        {
            public SmalLibData myDb = new SmalLibData(ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString);
    
            #region Private
    
            private int mUserID;
            private string mUserName;
            private string mMothersName;
            private string mAddress;
            private clsUserStatusBL mUserStatus = new clsUserStatusBL();
    
            #endregion
    
            #region Properties
    
            public int UserID
            {
                get { return mUserID; }
                set { mUserID = value; }
            }
    
            public string UserName
            {
                get { return mUserName; }
                set { mUserName = value; }
            }
    
            public string MothersName
            {
                get { return mMothersName; }
                set { mMothersName = value; }
            }
    
            public string Address
            {
                get { return mAddress; }
                set { mAddress = value; }
            }
    
            public clsUserStatusBL UserStatus
            {
                get { return mUserStatus; }
                set { mUserStatus = value; }
            }
            #endregion
    
            public IQueryable GetAllUsers()
            {
    
                return from c in myDb.User
                       from us in myDb.UserStatus
                       where c.UserStatusID == us.UserStatusID
                       //join us in objUserDal.GetUserStatus() on c.UserStatusID equals us.UserStatusID
                       select new
                       {
                           UserID = c.UserID,
                           UserName = c.UserName,
                           MothersName = c.MothersName,
                           Address = c.Address,
                           UserStatusDef = us.UserStatusDef
                       };
            }
    
    
            public Boolean Reccord(string _Action)
            {
                User user = new User();
    
                Boolean Success = true;
    
                switch (_Action)
                {
                    case "Insert":
                        user.UserName = mUserName;
                        user.MothersName = mMothersName;
                        user.Address = mAddress;
                        user.UserStatusID = mUserStatus.UserStatusID;
    
                        myDb.User.InsertOnSubmit(user);
                        break;
    
                    case "Update":
                        user = myDb.User.Where(c => c.UserID == mUserID).First<User>();
    
                        user.UserName = mUserName;
                        user.MothersName = mMothersName;
                        user.Address = mAddress;
                        user.UserStatusID = mUserStatus.UserStatusID;
                        break;
    
                    case "Delete":
                        user = myDb.User.Where(c => c.UserID == mUserID).First<User>();
    
                        myDb.User.DeleteOnSubmit(user);
                        break;
                }
    
                try
                {
                    // Submit changes to the database.  Executes the Insert, Update, or Delete query.
                    myDb.SubmitChanges();
                    Success = true;
                }
                catch (ChangeConflictException)
                {
                    // Resolving conflicts
                    Success = false;
                    myDb.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);
                }
    
                return Success;
            }
    The question now is, what steps to take in order to retrieve a single cells value from the selected row in the wpf datagrid?
    I tried to implement the method mentioned above, but somehow wasn't succesfull.  Can somebody please point me in the right direction...
    • Proposed as answer by ursri Thursday, January 21, 2010 7:11 AM
    Wednesday, December 2, 2009 6:37 PM
  • Selected Propose as answer to prev. msg. by mistake.


    CSven,


    Would this link http://www.scottlogic.co.uk/blog/colin/2008/12/wpf-datagrid-detecting-clicked-cell-and-row/ of any use? I think with this method, extra coding is required to map column to bound object property to get cell value...
    • Edited by ursri Thursday, January 21, 2010 7:36 AM corrected
    Thursday, January 21, 2010 7:33 AM
  • This is how I resolved this problem.  Make a class for the table in the database like this:

    public SmalLibData myDb = new SmalLibData(ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString);
    
            #region Private
    
            private string mISBN;
            private string mItemTitle;
            private int mPublishingYear;
            private int mNumberOfPages;
            private string mItemNotes;
    
            private clsAuthorBL mAuthor = new clsAuthorBL();
    
            #endregion
    
            #region Properties(Constructors)

     public string ISBN { get { return mISBN; } set { mISBN = value; } } public string ItemTitle { get { return mItemTitle; } set { mItemTitle = value; } } public int PublishingYear { get { return mPublishingYear; } set { mPublishingYear = value; } } public int NumberOfPages { get { return mNumberOfPages; } set { mNumberOfPages = value; } } public string ItemNotes { get { return mItemNotes; } set { mItemNotes = value; } } public clsAuthorBL Author { get { return mAuthor; } set { mAuthor = value; } } public string AuthorName { get { return mAuthor.AuthorName; } set { mAuthor.AuthorName = value; } } #endregion public List<clsItemBL> GetAllItems()
    {
    return (from it in myDb.Item
    from au in myDb.Author
    from itBau in myDb.ItemByAuthor
    where it.ISBNNumber == itBau.ISBNNumber
    where au.AuthorID == itBau.AuthorID
    select new clsItemBL
    {
    ISBN = it.ISBNNumber,
    ItemTitle = it.ItemTitle,
    AuthorName = au.AuthorName,
    PublishingYear = Convert.ToInt32(it.PublishingYear),
    NumberOfPages = it.NumberOfPages
    }).ToList();
    }
    It's important that you have constructors for each field (ISBNNumber, ItemTitle etc.) that you use in the select of the query.

    The DataGrid is populated in the following way:

    clsItemsBL objItem = new clsItemBL();

    dgItemSearch.ItemsSource = objItem.GetAllItems();


    Than in the code of the form where you DataGrid is you can do tha casting like this (usually this is done in the selected item changed for that DataGrid).  This way than you can acces each property of the selected item in the DataGrid.

    clsItemBL ItemSelection = (clsItemBL)dgItemSearch.SelectedItem;
    
    tbItemSearch.Text = ItemSelection.AuthorName;




    • Edited by CSevn Thursday, January 21, 2010 9:59 AM Added how to populate DataGrid.
    • Proposed as answer by CSevn Thursday, January 21, 2010 9:59 AM
    Thursday, January 21, 2010 9:51 AM
  • Will dataview be of any use?

    Friday, January 22, 2010 9:19 AM
  • Thank you very much.
    Thursday, December 12, 2013 12:10 PM