使用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); }
您必须使用正确的数据绑定技术,然后这将自动运行。
需要…
- 在ObservableCollection中的类上实现INotifyPropertyChanged(并确保在设置该类的属性时触发事件)
- 在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项后……
此处提供完整的代码示例: CODE SAMPLE
您已经遇到了ObservableCollection的经典问题。 它仅在添加或删除项目时通知。 它不会在集合中项目的属性发生更改时通知。 如果您希望收到此类更改的通知,则必须手动创建自己的自定义集合并在单个对象上添加/删除属性更改事件。 对不起,老兄。