ObservableCollection在其中的项目更改时不会注意到(即使使用INotifyPropertyChanged)

有谁知道为什么这个代码不起作用:

public class CollectionViewModel : ViewModelBase { public ObservableCollection<EntityViewModel> ContentList { get { return _contentList; } set { _contentList = value; RaisePropertyChanged("ContentList"); //I want to be notified here when something changes..? //debugger doesn't stop here when IsRowChecked is toggled } } } public class EntityViewModel : ViewModelBase { private bool _isRowChecked; public bool IsRowChecked { get { return _isRowChecked; } set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); } } } 

PS:ViewModelBase containts的一切为RaisePropertyChanged等,它的一切工作,除了这个问题。

当您更改集合中的值时,ContentList的Set方法将不会被调用,而是应该查找CollectionChanged事件触发。

 public class CollectionViewModel : ViewModelBase { public ObservableCollection<EntityViewModel> ContentList { get { return _contentList; } } public CollectionViewModel() { _contentList = new ObservableCollection<EntityViewModel>(); _contentList.CollectionChanged += ContentCollectionChanged; } public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { //This will get called when the collection is changed } } 

编辑

好的,今天有两次我被MSDN文档搞错了。 在我给你的链接里说:

在添加,删除,更改,移动项目或刷新整个列表时发生。

但是当一个项目被改变时,它实际上不会被触发。 我想你会需要一个更强大的方法:

 public class CollectionViewModel : ViewModelBase { public ObservableCollection<EntityViewModel> ContentList { get { return _contentList; } } public CollectionViewModel() { _contentList = new ObservableCollection<EntityViewModel>(); _contentList.CollectionChanged += ContentCollectionChanged; } public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Remove) { foreach(EntityViewModel item in e.OldItems) { //Removed items item.PropertyChanged -= EntityViewModelPropertyChanged; } } else if (e.Action == NotifyCollectionChangedAction.Add) { foreach(EntityViewModel item in e.NewItems) { //Added items item.PropertyChanged += EntityViewModelPropertyChanged; } } } public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { //This will get called when the property of an object inside the collection changes } } 

如果您需要这么多,您可能需要inheritance自己的ObservableCollection ,当成员自动触发其PropertyChanged事件时触发CollectionChanged事件(就像它在文档中所说的那样)

这是一个子类ObservableCollection的embedded类,当列表项的属性发生变化时,实际上会引发一个Reset操作。 它强制执行INotifyPropertyChanged所有项目。

这样做的好处是你可以将数据绑定到这个类,并且所有的绑定都会随着你的item属性的更改而更新。

 public sealed class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { public TrulyObservableCollection() { CollectionChanged += FullObservableCollectionCollectionChanged; } public TrulyObservableCollection(IEnumerable<T> pItems) : this() { foreach (var item in pItems) { this.Add(item); } } private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Object item in e.NewItems) { ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged; } } if (e.OldItems != null) { foreach (Object item in e.OldItems) { ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged; } } } private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e) { NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender)); OnCollectionChanged(args); } } 

这使用了上面的想法,但是使它成为一个派生的“更敏感”的集合:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Collections; namespace somethingelse { public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged { // this collection also reacts to changes in its components' properties public ObservableCollectionEx() : base() { this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged); } void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Remove) { foreach(T item in e.OldItems) { //Removed items item.PropertyChanged -= EntityViewModelPropertyChanged; } } else if (e.Action == NotifyCollectionChangedAction.Add) { foreach(T item in e.NewItems) { //Added items item.PropertyChanged += EntityViewModelPropertyChanged; } } } public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); OnCollectionChanged(args); } } } 

我已经放在一起,我希望是一个非常强大的解决scheme,其中包括一些其他答案的技术。 这是一个派生自ObservableCollection<>的新类,我称其为FullyObservableCollection<>

它具有以下特点:

  • 它添加了一个新的事件ItemPropertyChanged 。 我故意将这与现有的CollectionChanged分开:
    • 为了帮助向后兼容。
    • 因此可以在伴随它的新的ItemPropertyChangedEventArgs中给出更多相关的细节:原始的PropertyChangedEventArgs和集合中的索引。
  • 它复制了ObservableCollection<>所有构造函数。
  • 它正确地处理被重置的列表( ObservableCollection<>.Clear() ),避免了可能的内存泄漏。
  • 它覆盖了基类的OnCollectionChanged() ,而不是资源密集型的CollectionChanged事件。

完整的.cs文件如下。 请注意,已经使用了C#6的一些function,但是它应该相当简单:

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; namespace Utilities { public class FullyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { /// <summary> /// Occurs when a property is changed within an item. /// </summary> public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged; public FullyObservableCollection() : base() { } public FullyObservableCollection(List<T> list) : base(list) { ObserveAll(); } public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable) { ObserveAll(); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) { foreach (T item in e.OldItems) item.PropertyChanged -= ChildPropertyChanged; } if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace) { foreach (T item in e.NewItems) item.PropertyChanged += ChildPropertyChanged; } base.OnCollectionChanged(e); } protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e) { ItemPropertyChanged?.Invoke(this, e); } protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e) { OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e)); } protected override void ClearItems() { foreach (T item in Items) item.PropertyChanged -= ChildPropertyChanged; base.ClearItems(); } private void ObserveAll() { foreach (T item in Items) item.PropertyChanged += ChildPropertyChanged; } private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) { T typedSender = (T)sender; int i = Items.IndexOf(typedSender); if (i < 0) throw new ArgumentException("Received property notification from item not in collection"); OnItemPropertyChanged(i, e); } } /// <summary> /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event. /// </summary> public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs { /// <summary> /// Gets the index in the collection for which the property change has occurred. /// </summary> /// <value> /// Index in parent collection. /// </value> public int CollectionIndex { get; } /// <summary> /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class. /// </summary> /// <param name="index">The index in the collection of changed item.</param> /// <param name="name">The name of the property that changed.</param> public ItemPropertyChangedEventArgs(int index, string name) : base(name) { CollectionIndex = index; } /// <summary> /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class. /// </summary> /// <param name="index">The index.</param> /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param> public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName) { } } } 

所以你可以检查你可能做出的改变(看看我testing过的东西!),我也为它创build了一个NUnittesting类。 NB这使用PRISM的BindableBase实现INotifyPropertyChanged 。 显然,下面的代码是不需要的只是在你的项目中使用类。

 using NUnit.Framework; using Utilities; using Microsoft.Practices.Prism.Mvvm; using System.Collections.Specialized; using System.Collections.Generic; namespace Test_Utilities { [TestFixture] public class Test_FullyObservableCollection : AssertionHelper { public class NotifyingTestClass : BindableBase { public int Id { get { return _Id; } set { SetProperty(ref _Id, value); } } private int _Id; public string Name { get { return _Name; } set { SetProperty(ref _Name, value); } } private string _Name; } FullyObservableCollection<NotifyingTestClass> TestCollection; NotifyingTestClass Fred; NotifyingTestClass Betty; List<NotifyCollectionChangedEventArgs> CollectionEventList; List<ItemPropertyChangedEventArgs> ItemEventList; [SetUp] public void Init() { Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" }; Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" }; TestCollection = new FullyObservableCollection<NotifyingTestClass>() { Fred, new NotifyingTestClass() {Id = 2, Name = "Barney" }, new NotifyingTestClass() {Id = 3, Name = "Wilma" } }; CollectionEventList = new List<NotifyCollectionChangedEventArgs>(); ItemEventList = new List<ItemPropertyChangedEventArgs>(); TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e); TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e); } // Change existing member property: just ItemPropertyChanged(IPC) should fire [Test] public void DetectMemberPropertyChange() { TestCollection[0].Id = 7; Expect(CollectionEventList.Count, Is.EqualTo(0)); Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count"); Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name"); Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index"); } // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire [Test] public void DetectNewMemberPropertyChange() { TestCollection.Add(Betty); Expect(TestCollection.Count, Is.EqualTo(4)); Expect(TestCollection[3].Name, Is.EqualTo("Betty")); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count"); Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count"); Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)"); Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count"); Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count"); Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference"); CollectionEventList.Clear(); // Empty for next operation ItemEventList.Clear(); TestCollection[3].Id = 7; Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count"); Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count"); Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference"); } // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change [Test] public void CeaseListentingWhenMemberRemoved() { TestCollection.Remove(Fred); Expect(TestCollection.Count, Is.EqualTo(2)); Expect(TestCollection.IndexOf(Fred), Is.Negative); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)"); Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)"); Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)"); Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count"); Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count"); Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference"); CollectionEventList.Clear(); // Empty for next operation ItemEventList.Clear(); Fred.Id = 7; Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)"); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)"); } // Move member in list, change property: CPC should fire for move, IPC should fire for change [Test] public void MoveMember() { TestCollection.Move(0, 1); Expect(TestCollection.Count, Is.EqualTo(3)); Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0)); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)"); Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)"); Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)"); Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count"); Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count"); Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference"); Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference"); CollectionEventList.Clear(); // Empty for next operation ItemEventList.Clear(); Fred.Id = 7; Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)"); Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)"); Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference"); } // Clear list, chnage property: only CPC should fire for clear and neither for property change [Test] public void ClearList() { TestCollection.Clear(); Expect(TestCollection.Count, Is.EqualTo(0)); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)"); Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)"); Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)"); Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count"); Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count"); CollectionEventList.Clear(); // Empty for next operation ItemEventList.Clear(); Fred.Id = 7; Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)"); Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)"); } } } 

ObservableCollection不会传播单个项目更改为CollectionChanged事件。 您将需要订阅每个事件并手动转发,或者您可以查看BindingList [T]类,它将为您执行此操作。

添加到TruelyObservableCollection事件“ItemPropertyChanged”中:

 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 } 

我用Jack Kenyons的回答来实施我自己的OC,但是我想指出一个我必须做出的改变才能实现。 代替:

  if (e.Action == NotifyCollectionChangedAction.Remove) { foreach(T item in e.NewItems) { //Removed items item.PropertyChanged -= EntityViewModelPropertyChanged; } } 

我用这个:

  if (e.Action == NotifyCollectionChangedAction.Remove) { foreach(T item in e.OldItems) { //Removed items item.PropertyChanged -= EntityViewModelPropertyChanged; } } 

看来,如果行动是“e.NewItems”,则产生null。

只需在这个话题上增加2美分。 感觉TrulyObservableCollection需要使用ObservableCollection发现的另外两个构造函数:

 public TrulyObservableCollection() : base() { HookupCollectionChangedEvent(); } public TrulyObservableCollection(IEnumerable<T> collection) : base(collection) { foreach (T item in collection) item.PropertyChanged += ItemPropertyChanged; HookupCollectionChangedEvent(); } public TrulyObservableCollection(List<T> list) : base(list) { list.ForEach(item => item.PropertyChanged += ItemPropertyChanged); HookupCollectionChangedEvent(); } private void HookupCollectionChangedEvent() { CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged); } 

我知道我为这个派对太晚了,但也许 – 这对某个人有帮助。

在这里你可以find我的ObservableCollectionEx实现。 它有一些特点:

  • 它支持来自ObservableCollection的所有内容
  • 它是线程安全的
  • 它支持ItemPropertyChanged事件(每当Item.PropertyChanged项被触发时引发)
  • 它支持filter(所以,你可以创buildObservableCollectionEx,将其他集合作为源传递给它,并使用简单的谓词过滤。在WPF中非常有用,我在这个应用程序中使用了这个function)。 甚至更多 – 通过INotifyPropertyChanged界面过滤跟踪项目的变化。

当然,任何意见都表示赞赏;)

我使用的标准observablecollection的简单解决scheme:

不要添加到您的财产或直接更改它的内部项目,而是创build一些像这样的临时集合

 ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>(); 

并添加项目或对tmpList进行更改,

 tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example tmpList[0].IsRowChecked= true; //Example ... 

然后通过任务传递给你的实际财产。

 ContentList=tmpList; 

这将改变整个属性,导致通知INotifyPropertyChanged你需要的。

我尝试了这个解决scheme,但是只有在RaisePropertyChange(“SourceGroupeGridView”)对集合进行更改时才适用于我,因为每个项目添加或更改都会触发。

问题在于:

 public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); OnCollectionChanged(args); } 

NotifyCollectionChangedAction.Reset这个动作在groupedgrid中完成所有项目的重新绑定,等同于RaisePropertyChanged。 当你使用它时,所有的gridview组刷新。

如果你只想在UI中刷新新项目的组,你不需要使用Reset操作,你需要在itemproperty中模拟一个Add操作,如下所示:

 void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { var index = this.IndexOf((T)sender); this.RemoveAt(index); this.Insert(index, (T)sender); var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender); OnCollectionChanged(a); } 

对不起,我的英文,谢谢你的基本代码:),我希望这可以帮助别人^ _ ^

Enjoi!

这是我的版本的实现。 它检查并抛出一个错误,如果列表中的对象没有实现INotifyPropertyChanged,所以在开发时不能忘记这个问题。 在外部使用ListItemChanged事件确定列表或列表项本身是否已经改变。

 public class SpecialObservableCollection<T> : ObservableCollection<T> { public SpecialObservableCollection() { this.CollectionChanged += OnCollectionChanged; } void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { AddOrRemoveListToPropertyChanged(e.NewItems,true); AddOrRemoveListToPropertyChanged(e.OldItems,false); } private void AddOrRemoveListToPropertyChanged(IList list, Boolean add) { if (list == null) { return; } foreach (object item in list) { INotifyPropertyChanged o = item as INotifyPropertyChanged; if (o != null) { if (add) { o.PropertyChanged += ListItemPropertyChanged; } if (!add) { o.PropertyChanged -= ListItemPropertyChanged; } } else { throw new Exception("INotifyPropertyChanged is required"); } } } void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e) { OnListItemChanged(this, e); } public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e); public event ListItemChangedEventHandler ListItemChanged; private void OnListItemChanged(Object sender, PropertyChangedEventArgs e) { if (ListItemChanged != null) { this.ListItemChanged(this, e); } } } 

这是上述解决scheme的扩展方法…

 public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list) where T : INotifyPropertyChanged { var newList = new TrulyObservableCollection<T>(); if (list != null) { list.ForEach(o => newList.Add(o)); } return newList; } 

而不是ObservableCollection或TrulyObservableCollection,请考虑使用BindingList并调用ResetBindings方法。

例如:

 private BindingList<TfsFile> _tfsFiles; public BindingList<TfsFile> TfsFiles { get { return _tfsFiles; } set { _tfsFiles = value; NotifyPropertyChanged(); } } 

给定一个事件,比如点击你的代码看起来像这样:

 foreach (var file in TfsFiles) { SelectedFile = file; file.Name = "Different Text"; TfsFiles.ResetBindings(); } 

我的模型看起来像这样:

 namespace Models { public class TfsFile { public string ImagePath { get; set; } public string FullPath { get; set; } public string Name { get; set; } public string Text { get; set; } } } 

如果我知道ObservableCollection使事件只有当我们添加/删除或移动我们收集的项目。 当我们模拟更新集合项集合中的某些属性时,不会指示它,UI也不会更新。

你可以在你的Model类中模拟实现INotifyPropertyChange 。 而当我们更新收集项目中的一些propery时,它会自动更新UI。

 public class Model:INotifyPropertyChange { //... } 

然后

 public ObservableCollection<Model> {get; set;} 

在我的情况下,我用ListView绑定这个集合,并在ItemTemplate设置绑定到模型属性,它的工作很好。

这是一些片段

Windows XAML:

 <Window.DataContext> <local:ViewModel/> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <ListView Margin="10" BorderBrush="Black" HorizontalAlignment="Center" SelectedItem="{Binding SelectedPerson}" ItemsSource="{Binding Persons}"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Label Content="{Binding Name}"/> <Label Content="-"/> <Label Content="{Binding Age}"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> <Grid Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Label VerticalAlignment="Center" Content="Name:"/> <TextBox Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="10" Grid.Column="1" Width="100"/> <Label VerticalAlignment="Center" Grid.Row="1" Content="Age:"/> <TextBox Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="10" Grid.Row="1" Grid.Column="1" Width="100"/> </Grid> </Grid> 

Model code example:

 public class PersonModel:INotifyPropertyChanged { public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } public int Age { get => _age; set { _age = value; OnPropertyChanged(); } } private string _name; private int _age; //INotifyPropertyChanged implementation public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

And ViewModel implementation:

  public class ViewModel:INotifyPropertyChanged { public ViewModel() { Persons = new ObservableCollection<PersonModel> { new PersonModel { Name = "Jack", Age = 30 }, new PersonModel { Name = "Jon", Age = 23 }, new PersonModel { Name = "Max", Age = 23 }, }; } public ObservableCollection<PersonModel> Persons { get;} public PersonModel SelectedPerson { get => _selectedPerson; set { _selectedPerson = value; OnPropertyChanged(); } } //INotifyPropertyChanged Implementation public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private PersonModel _selectedPerson; }