使用ObservableCollection未正确更新ListView

我目前正在使用一个可观察的集合来存储我的ListView数据对象。 将新对象添加到集合中工作正常,listView正确更新。 但是,当我尝试更改集合中对象的某个属性时,listView将无法正确更新。 例如,我有一个可观察的集合DataCollection。 我试试

_DataCollections.ElementAt(count).Status = "Active"; 

由于按下按钮,我在长时间操作之前执行此更改。 listView不会反映更改。 所以我添加myListView.Items.Refresh() 这是有效的,但是在button_click方法完成之前,listView不会刷新,这在那时是不行的。 例如:

  button1_Click(...) { _DataCollections.ElementAt(count).Status = "Active"; myListView.Items.Refresh(); ExecuteLongOperation(); _DataCollections.ElementAt(count).Status = "Finished"; myListView.Items.Refresh(); } 

状态永远不会转到“活动”,它将在方法完成后直接进入“完成”。 我也尝试使用这样的调度程序:

 button1_Click(...) { this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Active"; myListView.Items.Refresh(); }); ExecuteLongOperation(); this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Finished"; myListView.Items.Refresh(); }); } 

但是,这似乎也不正常。 任何提示或想法将不胜感激。

为了解决这个问题,我创建了一个名为VeryObservableCollection的类。 对于您添加的每个对象,它将对象的NotifyPropertyChanged事件挂钩到触发CollectionChanged事件的处理程序。 对于删除的每个对象,它将删除处理程序。 很简单,会给你你想要的。 部分代码:

 public class VeryObservableCollection : ObservableCollection ///  /// Override for setting item ///  /// Index /// Item protected override void SetItem(int index, T item) { try { INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged; if (propOld != null) propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged); } catch (Exception ex) { Exception ex2 = ex.InnerException; } INotifyPropertyChanged propNew = item as INotifyPropertyChanged; if (propNew != null) propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged); base.SetItem(index, item); } 

您必须使用正确的数据绑定技术,然后这将自动运行。

需要…

  1. 在ObservableCollection中的类上实现INotifyPropertyChanged(并确保在设置该类的属性时触发事件)
  2. 在ListView的ItemTemplate上,确保使用Binding属性

如果你做这两件事,就不需要“刷新”电话或其他任何东西。 设置触发INotifyPropertyChanged的属性将导致ItemTemplate的绑定更新。

在ObservableCollection中的类上实现INotifyPropertyChanged … (如果你还不知道它,请查看BindableBase类)

 public class ToDoItem : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _name; public string Name { get { return _name; } set { SetProperty(ref _name, value); } } private DateTime _date; public DateTime Date { get { return _date; } set { SetProperty(ref _date, value); } } protected bool SetProperty(ref T storage, T value, [CallerMemberName]string propertyName = null) { if (object.Equals(storage, value)) return false; storage = value; this.OnPropertyChanged(propertyName); return true; } protected void OnPropertyChanged(string propertyName) { var eventHandler = this.PropertyChanged; if (eventHandler != null) { eventHandler(this, new PropertyChangedEventArgs(propertyName)); } } } 

你的ListView

           

你的ObservableCollection ……

 private ObservableCollection _toDoItems = new ObservableCollection(); // Assign the collection to the ListView listView.ItemsSource = _toDoItems; 

将东西添加到集合中……

 _toDoItems.Add(new ToDoItem() { Name = "Item " + (_toDoItems.Count + 1), Date = DateTime.Now }); 

更新,你要求的,工作……

 ToDoItem item = _toDoItems[randomIndex]; item.Name = "Updated " + item.Name; item.Date = DateTime.Now; 

无需调用“刷新”或其他任何需要的东西。 项目本身会更新,而不会更改列表。

在更新第4项之前……

在更新第4项之前

更新第4项后……

更新第4项后

此处提供完整的代码示例: CODE SAMPLE

您已经遇到了ObservableCollection的经典问题。 它仅在添加或删除项目时通知。 它不会在集合中项目的属性发生更改时通知。 如果您希望收到此类更改的通知,则必须手动创建自己的自定义集合并在单个对象上添加/删除属性更改事件。 对不起,老兄。