wpf 用另一个 ObservableCollection 替换整个 ObservableCollection
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17996542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace Entire ObservableCollection with another ObservableCollection
提问by Adam Szabo
public class Alpha
{
public ObservableCollection<Beta> Items { get; set; }
public Alpha()
{
Items = new ObservableCollection<Beta>();
}
public void DoSomething()
{
Items = GetNewItems(); // whenever I do this, Items gets a new referene,
// so every WPF binding (e.g. datagrids) are broken
}
public ObservableCollection<Beta> GetNewItems()
{
var ret = new ObservableCollection<Beta>();
// some logic for getting some items from somewhere, and populating ret
return ret;
}
}
How can I replace the whole content of Itemswith the return value of GetNewItems()without:
如何Items用GetNewItems()without的返回值替换 的全部内容:
Breaking the bindings.
Having to loop through the items and copy them one by one to the other collection ?
打破束缚。
必须遍历项目并将它们一个一个地复制到另一个集合中?
采纳答案by Ty Morrow
You have some options:
你有一些选择:
- Implement INotifyPropertyChanged so you can inform the UI that the value of Items has changed. This does not utilize the fact that INotifyCollectionChanged is implemented on ObservableCollection. It will work, but it defeats the purpose of using an ObservableCollection in the first place. This is not recommended but it works.
- Use the ObservableCollection's Add/Remove/Modify/Update methods to modify it in conjunction with the Dispatcher.
- Note: without the Dispatcher, you will get a NotSupportedException because CollectionViews do not support changes to their SourceCollection from a thread different from the Dispatcher thread.
- Use the ObservableCollection's Add/Remove/Modify/Update methods to modify it in conjunction with
BindingOperations.EnableCollectionSynchronization. Recommended- Note: This is only available in .NET 4.5.
- This is an alternative to using the Dispatcher while avoiding the NotSupportedException.
- Example
- 实现 INotifyPropertyChanged,以便您可以通知 UI Items 的值已更改。这不利用 INotifyCollectionChanged 在 ObservableCollection 上实现的事实。它会起作用,但它首先违背了使用 ObservableCollection 的目的。不推荐这样做,但它有效。
- 使用 ObservableCollection 的 Add/Remove/Modify/Update 方法与 Dispatcher 一起修改它。
- 注意:如果没有 Dispatcher,您将得到 NotSupportedException,因为CollectionViews 不支持从不同于 Dispatcher thread 的线程更改它们的 SourceCollection。
- 使用 ObservableCollection 的 Add/Remove/Modify/Update 方法结合
BindingOperations.EnableCollectionSynchronization. 受到推崇的- 注意:这仅在 .NET 4.5 中可用。
- 这是使用 Dispatcher 的替代方法,同时避免 NotSupportedException。
- 例子
Numbers 2 and 3, with respect to your question, translate to clearing the existing items (Clear()) and then adding (Add()) the items returned by whatever method you want - see the example for #3. They key is that the clearing and all of the adding must be done with Dispatcher (2) or by calling BindingOperations.EnableCollectionSynchronization.
Good luck!
关于您的问题,数字 2 和 3 转换为清除现有项目 (Clear()),然后添加 (Add()) 由您想要的任何方法返回的项目 - 请参阅 #3 的示例。它们的关键是清除和所有添加必须使用 Dispatcher (2) 或通过调用BindingOperations.EnableCollectionSynchronization. 祝你好运!
Reference: Reed Copsey Answer - StackOverflow
回答by Jakub Pawlinski
You can also make your own class that will extend the ObservableCollection, here is an example with notifications sorted:
您还可以创建自己的类来扩展 ObservableCollection,这是一个排序通知的示例:
https://github.com/jamesmontemagno/mvvm-helpers/blob/master/MvvmHelpers/ObservableRangeCollection.cs
https://github.com/jamesmontemagno/mvvm-helpers/blob/master/MvvmHelpers/ObservableRangeCollection.cs
I'm using simpler implementation of above (I did not compared the notification aspect yet):
我正在使用上述更简单的实现(我还没有比较通知方面):
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
{
/// <summary>
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
//INotifyPropertyChanged interited from ObservableCollection<T>
#region INotifyPropertyChanged
protected override event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
/// <summary>
/// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
/// </summary>
public void AddRange(IEnumerable<T> collection)
{
if (collection == null) throw new ArgumentNullException(nameof(collection));
foreach (var i in collection) Items.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T).
/// </summary>
public void RemoveRange(IEnumerable<T> collection)
{
if (collection == null) throw new ArgumentNullException(nameof(collection));
foreach (var i in collection) Items.Remove(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Clears the current collection and replaces it with the specified item.
/// </summary>
public void Replace(T item)
{
Replace(new T[] { item });
}
/// <summary>
/// Replaces all elements in existing collection with specified collection of the ObservableCollection(Of T).
/// </summary>
public void Replace(IEnumerable<T> collection)
{
if (collection == null) throw new ArgumentNullException(nameof(collection));
Items.Clear();
foreach (var i in collection) Items.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
/// </summary>
public ObservableCollectionEx()
: base() { }
/// <summary>
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
/// </summary>
/// <param name="collection">collection: The collection from which the elements are copied.</param>
/// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception>
public ObservableCollectionEx(IEnumerable<T> collection)
: base(collection) { }
}
}
}
回答by Shoe
ObservableCollection implements INotifyCollectionChanged, which will update bindings whenever items get added or removed. All that is needed here is to clear the list for the CollectionChanged event to fire.
ObservableCollection 实现了 INotifyCollectionChanged,它会在添加或删除项目时更新绑定。这里所需要做的就是清除要触发的 CollectionChanged 事件的列表。
public void GetNewItems()
{
Items.Clear();
// some logic for getting some items from somewhere, and populating ret
}

