Вот что я использую для просмотра коллекций моделей:
Предисловие:
Ваши объекты модели вида могут быть слабо напечатаны. Присвойте IModel
свойство object Value {get;}
и выставьте его в ModelViewModel : ViewModel<IModel>
, который вы используете для всех IModel
объектов (см. Мою реализацию ViewModel<T>
ниже). Если у вас есть различные комбинации ObservableCollection<IModel>
, ICollection<Model<T>>
и т. Д., Показанная здесь структура спасет вас. Если вам все еще нужна модель общего вида, вы можете получить ModelViewModel<T> : ModelViewModel
, который принимает Model<T>
в своем конструкторе. Логика для создания соответствующего типа будет идти в преобразователе, переданном в ViewModelCollection.Create
ниже. Имейте в виду, что этот дизайн налагает штраф производительности.
ModelViewModel CreateModelViewModel(IModel model)
{
Type viewModelType = typeof(ModelViewModel<>).MakeGenericType(model.Type);
ModelViewModel viewModel = Activator.CreateInstance(viewModelType, model);
return viewModel;
}
Пример использования:
public class CatalogViewModel : ViewModel<ICatalog>
{
public CatalogViewModel(ICatalog catalog)
: base(catalog)
{
Func<ICatalogProduct, ProductViewModel> viewModelFactory = CreateProductViewModel;
this.Products = ViewModelCollection.Create(catalog.Products, viewModelFactory);
}
public ICollection<ProductViewModel> Products
{
get;
private set;
}
private ProductViewModel CreateProductViewModel(ICatalogProduct product)
{
return new ProductViewModel(product, this);
}
}
Преимущества:
- Использует ленивые реализации, чтобы обеспечить эффективные и даже рекурсивные привязки в деревьях.
- Коллекции моделей представлений реализуют
INotifyCollectionChanged
, только если базовая коллекция моделей реализует INotifyCollectionChanged
.
Обзор классов (полные реализации, связанные с github):
ViewModel<TModel>
: Базовый класс для классов моделей моего вида. Предоставляет свойство Model
, которое я использую в коде поддержки модели представления.
ObservableViewModelCollection<TViewModel, TModel>
: Ленивый (на самом деле не в настоящее время, но определенно должен быть), наблюдаемый отображение из модель для просмотра модели. Реализует INotifyCollectionChanged
.
ViewModelCollection<TViewModel, TModel>
: Ленивый отображение из коллекции TModel в коллекцию TViewModel
.
ViewModelCollection
: Статический помощник - возвращает ICollection<TViewModel>
, используя ObservableViewModelCollection<TViewModel, TModel>
, когда исходная коллекция реализует INotifyCollectionChanged
, в противном случае используя ViewModelCollection<TViewModel, TModel>
.
Несколько дополнительных типов, которые могут быть полезны для ваших коллекций моделей представлений:
ConcatCollection
: Как и ViewModelCollection, он включает в себя статический помощник для автоматического выбора подходящей реализации. ConcatCollection объединяет коллекции, связываясь непосредственно с исходными коллекциями.
Вот пример того, как я использовал этот тип для представления свойства Children
представлению, сохраняя мои наблюдаемые коллекции вплоть до исходного источника.
public class ProductViewModel : ViewModel<IProduct>
{
public ProductViewModel(IProduct product)
: base(product)
{
Func<IProduct, ProductViewModel> productViewModelFactory = CreateProductViewModel;
Func<IRelease, ReleaseViewModel> releaseViewModelFactory = CreateReleaseViewModel;
this.Products = ViewModelCollection.Create(product.Products, productViewModelFactory);
this.Releases = ViewModelCollection.Create(product.Releases, releaseViewModelFactory);
this.Children = ConcatCollection.Create<object>((ICollection)this.Products, (ICollection)this.Releases);
}
public IList<ProductViewModel> Products
{
get;
private set;
}
public IList<ReleaseViewModel> Releases
{
get;
private set;
}
public IEnumerable<object> Children
{
get;
private set;
}
private ProductViewModel CreateProductViewModel(IProduct product)
{
return new ProductViewModel(product);
}
private ReleaseViewModel CreateReleaseViewModel(IRelease release)
{
return new ReleaseViewModel(release);
}
}