将整个ObservableCollection替换为另一个ObservableCollection

时间:2013-08-01 14:14:05

标签: c# wpf binding observablecollection

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;
    }
}

如何将Items的整个内容替换为GetNewItems()的返回值,而不是:

  1. 打破绑定。

  2. 必须遍历这些项目并将它们逐个复制到另一个集合中吗?

3 个答案:

答案 0 :(得分:7)

你有一些选择:

  1. 实施INotifyPropertyChanged,以便您可以通知UI项目的值已更改。这不利用在ObservableCollection上实现INotifyCollectionChanged的事实。它会起作用,但它首先违背了使用ObservableCollection的目的。这不推荐,但它有效。
  2. 使用ObservableCollection的Add / Remove / Modify / Update方法与Dispatcher一起修改它。
    • 注意:如果没有Dispatcher,您将收到NotSupportedException,因为 CollectionViews不支持从与Dispatcher线程不同的线程更改其SourceCollection。
  3. 使用ObservableCollection的添加/删除/修改/更新方法与BindingOperations.EnableCollectionSynchronization一起修改它。 <强>推荐
    • 注意:这仅适用于.NET 4.5。
    • 这是在避免使用NotSupportedException时使用Dispatcher的替代方法。
    • Example
  4. 关于您的问题,数字2和3转换为清除现有项目(Clear()),然后添加(Add())您想要的任何方法返回的项目 - 请参阅#3的示例。关键是清算和所有添加必须使用Dispatcher(2)或通过调用BindingOperations.EnableCollectionSynchronization来完成。 祝你好运!

    参考:Reed Copsey Answer - StackOverflow

答案 1 :(得分:3)

你也可以创建自己的类来扩展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
{
/// <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) { }
}

}

答案 2 :(得分:1)

ObservableCollection实现了INotifyCollectionChanged,它将在添加或删除项目时更新绑定。这里需要的只是清除要触发的CollectionChanged事件的列表。

public void GetNewItems()
{
     Items.Clear();

     // some logic for getting some items from somewhere, and populating ret

}