11
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. 必须遍历项目并将它们一一复制到另一个集合?

4

3 回答 3

11

你有一些选择:

  1. 实现 INotifyPropertyChanged,以便您可以通知 UI Items 的值已更改。这没有利用在 ObservableCollection 上实现 INotifyCollectionChanged 的​​事实。它会起作用,但它首先破坏了使用 ObservableCollection 的目的。不建议这样做,但它有效。
  2. 使用 ObservableCollection 的 Add/Remove/Modify/Update 方法与 Dispatcher 一起修改它。
    • 注意:如果没有 Dispatcher,您将收到 NotSupportedException,因为CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection
  3. 使用 ObservableCollection 的 Add/Remove/Modify/Update 方法结合BindingOperations.EnableCollectionSynchronization. 推荐的
    • 注意:这仅在 .NET 4.5 中可用。
    • 这是在避免 NotSupportedException 的同时使用 Dispatcher 的替代方法。
    • 例子

关于您的问题,数字 2 和 3 转换为清除现有项目 (Clear()),然后添加 (Add()) 您想要的任何方法返回的项目 - 请参见 #3 的示例。他们的关键是必须使用 Dispatcher (2) 或调用BindingOperations.EnableCollectionSynchronization. 祝你好运!

参考:Reed Copsey 答案 - StackOverflow

于 2013-08-01T14:23:22.157 回答
4

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

}

于 2016-09-21T10:44:16.453 回答
2

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

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

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

}
于 2013-08-01T14:31:27.940 回答