Answered by:
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 usingDataGridCell 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 DeepakSunday, 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.
That seems as a good solution to the problem, but how do I do this if I'm making a three layer application. Layer:
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
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);
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 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 };
}
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)
It's important that you have constructors for each field (ISBNNumber, ItemTitle etc.) that you use in the select of the query.
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();
}
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;
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