2013-06-20 2 views
7

Я пытаюсь реализовать свое первое приложение MVVM. Я мог связать данные в datagrid, но изменения, которые я делаю в элементах, не запускают метод RaisePropertyChanged модели.WPF: Связанный datagrid не обновляет свойства элементов

Это мой 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(); 

     } 
    } 

Модель, реализует класс NotificationObject, который обеспечивает 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 


} 

}

И, наконец, Вид:

<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> 

Что я забываю или делаю неправильно?

Заранее благодарен!

Оскар

ответ

5

Спасибо так много Loetn и Андраш Sebo, ваши ключи привели очень полезно! Решение, приведенное ниже, было принято мной, и оно отлично сработало !!!

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's a "TrulyObservableCollection" that's 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 
} 
2

Поскольку элементы находятся в коллекции и сама коллекция не меняется. Вы должны подписываться в классе UsersViewModel каждый UserModel, прежде чем добавлять его в коллекцию.

Вот возможное решение:

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

+0

Извините, что я действительно новичок, и этот пример похож на O_O 'для меня. О'кей, идея - это «специализированный» наблюдаемый коллектив, который заботится об изменениях? –

+0

это кажется действительно проводным, вы говорите мне, что ObservableCollection не обновляет элементы с ввода из ui? –

+1

ObservableCollection уведомляет ui _IF_, сама коллекция была изменена (добавлена, удалена, очищена, сброшена), но НЕ уведомляет ui, если свойство элемента в коллекции изменилось. Проверьте ответ от Loetn ниже, чтобы увидеть возможное обходное решение. –

3

Bind это событие к событию CollectionChanged вашего 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 
    } 
+0

Большое вам спасибо! –

+0

Нет проблем. Рад, что смог помочь. :) – Loetn

Смежные вопросы