将整个ObservableCollection替换为另一个ObservableCollection
public class Alpha { public ObservableCollection Items { get; set; } public Alpha() { Items = new ObservableCollection(); } public void DoSomething() { Items = GetNewItems(); // whenever I do this, Items gets a new referene, // so every WPF binding (eg datagrids) are broken } public ObservableCollection GetNewItems() { var ret = new ObservableCollection(); // some logic for getting some items from somewhere, and populating ret return ret; } }
如何在不使用GetNewItems()
的返回值的情况下替换Items
的整个内容:
-
打破绑定。
-
必须遍历项目并将它们逐个复制到另一个集合中?
你有一些选择:
- 实现INotifyPropertyChanged,以便您可以通知UI项的值已更改。 这不利用在ObservableCollection上实现INotifyCollectionChanged的事实。 它会起作用,但它首先违背了使用ObservableCollection的目的。 不建议这样做,但它有效。
- 例
- 使用ObservableCollection的Add / Remove / Modify / Update方法与Dispatcher一起修改它。
- 注意:如果没有Dispatcher,您将收到NotSupportedException,因为CollectionViews不支持从与Dispatcher线程不同的线程更改其SourceCollection 。
- 使用ObservableCollection的Add / Remove / Modify / Update方法将其与
BindingOperations.EnableCollectionSynchronization
一起修改。 推荐的- 注意:这仅适用于.NET 4.5。
- 这是在避免使用NotSupportedException时使用Dispatcher的替代方法。
- 例
关于你的问题,数字2和3转换为清除现有项目(Clear()),然后添加(Add())通过任何方法返回的项目 – 请参阅#3的示例。 它们的关键是清除和所有添加必须使用Dispatcher(2)或通过调用BindingOperations.EnableCollectionSynchronization
。 祝好运!
参考: Reed Copsey答案 – StackOverflow
您还可以创建自己的类来扩展ObservableCollection,这是一个通知排序的示例:
https://github.com/jamesmontemagno/mvvm-helpers/blob/master/MvvmHelpers/ObservableRangeCollection.cs
我正在使用上面更简单的实现(我没有比较通知方面):
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Runtime.CompilerServices; using BaseLibrary.Properties; namespace BaseLibrary { /// /// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. /// /// public class ObservableCollectionEx : ObservableCollection { //INotifyPropertyChanged interited from ObservableCollection #region INotifyPropertyChanged protected override event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] public void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion INotifyPropertyChanged /// /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). /// public void AddRange(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); foreach (var i in collection) Items.Add(i); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// /// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). /// public void RemoveRange(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); foreach (var i in collection) Items.Remove(i); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// /// Clears the current collection and replaces it with the specified item. /// public void Replace(T item) { Replace(new T[] { item }); } /// /// Replaces all elements in existing collection with specified collection of the ObservableCollection(Of T). /// public void Replace(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); Items.Clear(); foreach (var i in collection) Items.Add(i); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class. /// public ObservableCollectionEx() : base() { } /// /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection. /// /// collection: The collection from which the elements are copied. /// The collection parameter cannot be null. public ObservableCollectionEx(IEnumerable collection) : base(collection) { } }
}
ObservableCollection实现了INotifyCollectionChanged,它将在添加或删除项时更新绑定。 这里需要的只是清除要触发的CollectionChanged事件的列表。
public void GetNewItems() { Items.Clear(); // some logic for getting some items from somewhere, and populating ret }