WPF: замена содержимого коллекции данных без очистки / добавления - PullRequest
8 голосов
/ 29 ноября 2010

При использовании привязки данных WPF я, очевидно, не могу сделать что-то вроде MyCollection = new CollectionType<Whatever>( WhateverQuery() );, поскольку привязки имеют ссылку на старую коллекцию. Мой обходной путь до сих пор был MyCollection.Clear();, за которым следовал foreach, выполняющий MyCollection.Add(item); - что довольно плохо как для производительности, так и для эстетики.

ICollectionView, хотя и довольно аккуратный, также не решает проблему, так как его свойство SourceCollection доступно только для чтения; облом, так как это было бы хорошим и простым решением.

Как другие люди решают эту проблему? Стоит отметить, что я работаю с MVVM и поэтому не могу рыться в привязках отдельных элементов управления. Я полагаю, что мог бы сделать обертку вокруг ObservableCollection, используя ReplaceSourceCollection() метод, но перед тем, как пойти по этому пути, я хотел бы узнать, есть ли какая-нибудь другая лучшая практика.

EDIT:

Для WinForms я бы привязал элементы управления к BindingSource, что позволило бы мне просто обновить его свойство DataSource и вызвать метод ResetBindings() - presto, базовая коллекция эффективно изменилась. Я ожидал, что привязка данных WPF будет поддерживать подобный сценарий из коробки?

Пример (псевдо-иш) кода: элемент управления WPF (ListBox, DataGrid, что вы хотите) привязан к свойству Users. Я понимаю, что коллекции должны быть доступны только для чтения, чтобы избежать проблем, демонстрируемых ReloadUsersBad(), но тогда плохой код для этого примера, очевидно, не скомпилируется:)

public class UserEditorViewModel
{
    public ObservableCollection<UserViewModel> Users { get; set; }

    public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ }

    public void ReloadUsersBad()
    {
        // bad: the collection is updated, but the WPF control is bound to the old reference.
        Users = new ObservableCollection<User>( LoadUsersFromWhateverSource() );
    }

    public void ReloadUsersWorksButIsInefficient()
    {
        // works: collection object is kept, and items are replaced; inefficient, though.
        Users.Clear();
        foreach(var user in LoadUsersFromWhateverSource())
            Users.Add(user);
    }

    // ...whatever other stuff.
}

Ответы [ 2 ]

4 голосов
/ 29 ноября 2010

Если объект MyCollection имеет навесное оборудование INotifyPropertyChanged, вы можете просто заменить коллекцию.

Пример:

public class MyClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private ObservableCollection<Whatever> _myCollection;

    private void NotifyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public ObservableCollection<Whatever> MyCollection
    {
        get
        {
            return _myCollection;
        }
        set
        {
            if (!ReferenceEquals(_myCollection, value))
            {
                _myCollection = value;
                NotifyChanged("MyCollection");
            }
        }
    }
}

С этим,когда вы назначаете коллекцию, WPF обнаруживает это, и все обновляется.

Вот как я бы решил это.

1 голос
/ 29 ноября 2010

Ссылка ниже объясняет, как реализовать метод AddRange.

http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx

Похоже, вы застряли с реализацией подкласса, который правильно обрабатывает этот случай.

Видимо, некоторые элементы управления не поддерживают пакетные уведомления об изменениях коллекции.По крайней мере, они не сделали, когда эта статья была написана.Хотя теперь у вас должно быть немного больше информации, если вы хотите продолжить расследование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...