WPF: bound datagrid does not update element properties

I am trying to implement my first MVVM application. I could bind the data in a datagrid, but the changes I make in the elements do not trigger the RaisePropertyChanged method of the model.

This is My ViewModel

public class UsersViewModel : BaseViewModel { private static TOPEntities _context; private ObservableCollection<UserModel> _usersCollection; public UsersViewModel() { _usersCollection = new ObservableCollection<UserModel>(GetAllUsers()); } public ObservableCollection<UserModel> UsersCollection { get { return _usersCollection; } set { if (_usersCollection != value) { _usersCollection = value; RaisePropertyChanged(() => UsersCollection); } } } public static List<UserModel> GetAllUsers() { using (_context = new TOPEntities()) { return _context.Users.Select (user => new UserModel { Id_User = user.Id_User, Name = user.Name, Username = user.Username, Language = user.Language, Password = user.Password, Profile = user.Profile }).ToList(); } } 

The model implements the NotificationObject class, which provides INotifyPropertyChanged

  public class UserModel : NotificationObject { #region Construction /// Constructs the default instance of a UserModel public UserModel() { } #endregion #region Model Attributes private int _id_User; private string _username; private string _password; private string _profile; private string _name; private string _language; #endregion #region Properties public int Id_User { get { return _id_User; } set { if (_id_User != value) { _id_User = value; RaisePropertyChanged(() => Id_User); } } } public string Username { get { return _username; } set { if (_username != value) { _username = value; RaisePropertyChanged(() => Id_User); } } } public string Password { get { return _password; } set { if (_password != value) { _password = value; RaisePropertyChanged(() => Id_User); } } } public string Profile { get { return _profile; } set { if (_profile != value) { _profile = value; RaisePropertyChanged(() => Id_User); } } } public string Name { get { return _name; } set { if (_name != value) { _name = value; RaisePropertyChanged(() => Name); } } } public string Language { get { return _language; } set { if (_language != value) { _language = value; RaisePropertyChanged(() => Language); } } } #endregion } 

}

And finally, View:

 <Window x:Class="TOP2.Views.UsersView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:viewModels="clr-namespace:TOP2.ViewModels" xmlns:local="TOP2" Title="Sample App" WindowStartupLocation="CenterScreen" Height="459" Width="795"> <Window.Resources> <viewModels:UsersViewModel x:Key="Windows1ViewModel" /> </Window.Resources> <Grid DataContext="{StaticResource Windows1ViewModel}"> <DataGrid ItemsSource="{Binding UsersCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" HorizontalAlignment="Left" Margin="81,51,0,0" VerticalAlignment="Top" Height="332" Width="622"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid> </Grid> 

What am I forgetting or doing wrong?

Thanks in advance!

Oscar

+7
source share
3 answers

Thanks for so many Loetn and Andras Sebo, your tips really helped! The solution below was made by me, and it worked perfectly.

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; // ObservableCollection using System.ComponentModel; // INotifyPropertyChanged using System.Collections.Specialized; // NotifyCollectionChangedEventHandler using System.Linq; using System.Text; using System.Threading.Tasks; namespace ObservableCollectionTest { class Program { static void Main(string[] args) { // ATTN: Please note it a "TrulyObservableCollection" that instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main. // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>(); Trades.Add(new Trade { Symbol = "APPL", Qty = 123 }); Trades.Add(new Trade { Symbol = "IBM", Qty = 456}); Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 }); Trades.CollectionChanged += Trades_CollectionChanged; Trades.ItemPropertyChanged += PropertyChangedHandler; Trades.RemoveAt(2); Trades[0].Qty = 999; Console.WriteLine("Hit any key to exit"); Console.ReadLine(); return; } static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) { Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty); return; } static void Trades_CollectionChanged(object sender, EventArgs e) { Console.WriteLine(DateTime.Now.ToString() + ", Collection changed"); return; } } #region TrulyObservableCollection public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { public event PropertyChangedEventHandler ItemPropertyChanged; public TrulyObservableCollection() : base() { CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged); } void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Object item in e.NewItems) { (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); } } if (e.OldItems != null) { foreach (Object item in e.OldItems) { (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged); } } } void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); OnCollectionChanged(a); if (ItemPropertyChanged != null) { ItemPropertyChanged(sender, e); } } } #endregion #region Sample entity class Trade : INotifyPropertyChanged { protected string _Symbol; protected int _Qty = 0; protected DateTime _OrderPlaced = DateTime.Now; public DateTime OrderPlaced { get { return _OrderPlaced; } } public string Symbol { get { return _Symbol; } set { _Symbol = value; NotifyPropertyChanged("Symbol"); } } public int Qty { get { return _Qty; } set { _Qty = value; NotifyPropertyChanged("Qty"); } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } #endregion } 
+5
source

Bind this event to the CollectionChanged event of your ObservableCollection:

 private void ObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (var item in e.NewItems) { item.PropertyChanged += this.Item_PropertyChanged; } } if (e.OldItems != null) { foreach (var item in e.OldItems) { item.PropertyChanged -= this.Item_PropertyChanged; } } } private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { // do something } 
+3
source

Since the elements are in the collection, the collection itself does not change. You must subscribe in the UsersViewModel class for each UserModel change before adding it to the collection.

Here is a possible solution:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/c03b9edd-e9a9-4674-82d3-56caaf67d6d9/observablecollectiont-listen-for-changes-in-child-elements

+2
source

All Articles