My Model
is a generic class that contains a (for example) Value
property which can be int, float, string, bool, etc. So naturally this class is represe
Here's what I'm using for view model collections:
Your view model objects can be weakly typed. Give IModel
a property object Value {get;}
and expose that in a ModelViewModel : ViewModel
that you use for all IModel
objects (see my ViewModel
implementation below). If you have various combinations of ObservableCollection
, ICollection
, etc., the framework shown here is a lifesaver. If you still need generic view model, you can derive a ModelViewModel
that takes a Model
in its constructor. The logic to create the appropriate type would go in the converter passed to ViewModelCollection.Create
below. Do be warned that this design will impose a performance penalty.
ModelViewModel CreateModelViewModel(IModel model)
{
Type viewModelType = typeof(ModelViewModel<>).MakeGenericType(model.Type);
ModelViewModel viewModel = Activator.CreateInstance(viewModelType, model);
return viewModel;
}
public class CatalogViewModel : ViewModel
{
public CatalogViewModel(ICatalog catalog)
: base(catalog)
{
Func viewModelFactory = CreateProductViewModel;
this.Products = ViewModelCollection.Create(catalog.Products, viewModelFactory);
}
public ICollection Products
{
get;
private set;
}
private ProductViewModel CreateProductViewModel(ICatalogProduct product)
{
return new ProductViewModel(product, this);
}
}
INotifyCollectionChanged
if the underlying model collection implements INotifyCollectionChanged
.ViewModelModel
property that I use in the view model's backing code.
ObservableViewModelCollectionINotifyCollectionChanged
.
ViewModelCollectionTViewModel
.
ViewModelCollection: Static helper - returns an ICollection
, using ObservableViewModelCollection
when the source collection implements INotifyCollectionChanged
, otherwise using ViewModelCollection
.
ConcatCollection
: Like ViewModelCollection, this includes a static helper to automatically choose an appropriate implementation. The ConcatCollection concatenates collections by binding directly to the source collection(s).
Here is an example of how I used this type to expose a Children
property to the view while maintaining my observable collections all the way to back to the original source.
public class ProductViewModel : ViewModel
{
public ProductViewModel(IProduct product)
: base(product)
{
Func productViewModelFactory = CreateProductViewModel;
Func releaseViewModelFactory = CreateReleaseViewModel;
this.Products = ViewModelCollection.Create(product.Products, productViewModelFactory);
this.Releases = ViewModelCollection.Create(product.Releases, releaseViewModelFactory);
this.Children = ConcatCollection.Create