При использовании привязки данных 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.
}