2013-08-01 4 views
6
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() без:Заменить Весь ObservableCollection с другим ObservableCollection

  1. Рассекая привязки.

  2. Нужно ли перебирать предметы и копировать их один за другим в другую коллекцию?

+0

Привет @ user2270404, это было сделано в .NET 4.5? –

+0

@ The Red Lou: Нет, это было сделано в 4.0 –

+0

Ну, я просто хотел сообщить вам, что обновил меня на основе отзывов, если вы хотите взглянуть. Я нашел некоторые другие способы его решения и сделал примеры, но для третьего требуется .NET 4.5. –

ответ

7

У вас есть несколько вариантов:

  1. Реализовать INotifyPropertyChanged так что вы можете сообщить об этом пользовательском интерфейсе, что стоимость предметов изменилась. Это не использует тот факт, что INotifyCollectionChanged реализован на ObservableCollection. Он будет работать, но он побеждает цель использования ObservableCollection в первую очередь. Это не рекомендуется, но это работает.
  2. Использование Добавьте ObservableCollection/удаление методов/Изменить/Update, чтобы изменить его в сочетании с диспетчером.
    • Примечание: без диспетчера, вы получите NotSupportedException потому CollectionViews не поддерживают изменения в их SourceCollection из потока, отличного от Dispatcher нити.
  3. Используйте методы Add/Remove/Modify/Update ObservableCollection для его модификации в сочетании с BindingOperations.EnableCollectionSynchronization. Рекомендовано
    • Примечание: Это доступно только в .NET 4.5.
    • Это альтернатива использованию Диспетчера, избегая исключения NotSupportedException.
    • Example

Числа 2 и 3, по отношению к вашему вопросу, перевести на очистку существующих элементов (Clear()), а затем добавить (Add()) элементы, возвращаемые какой метод вы want - см. пример для # 3. Они указывают, что очистка и все добавление должны выполняться с Диспетчером (2) или путем вызова BindingOperations.EnableCollectionSynchronization. Удачи!

Ссылка: Reed Copsey Answer - StackOverflow

+1

Это не использует тот факт, что используется наблюдаемая сборка. – Shoe

+0

Как его можно улучшить? –

+0

Я согласен с обувью. Не имеет смысла добавлять второй механизм уведомления, когда существующий будет работать очень хорошо и создать более удобный для обслуживания код. – denver

1

ObservableCollection реализует INotifyCollectionChanged, который будет обновляться привязок, когда элементы будут добавлены или удалены. Все, что здесь необходимо, - это очистить список для события CollectionChanged.

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

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

} 
+1

Примечание: Это _can_ вызывает исключение NotSupportedException. –

+0

@ TheRedLou Можете ли вы это объяснить? Я не знаю об этом. – Shoe

+0

@TheRedLou В этом вопросе ничего не говорится о не-ui-потоке. – Shoe

2

Вы также можете создать свой собственный класс, который будет продлить 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) { } 
} 

}

Смежные вопросы