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 represented something like Model<T>
. For the sake of collections Model<T>
implements the interface IModel
, although IModel
is itself empty of any content.
My ViewModel
contains and instance of Model<T>
and it is passed in through ViewModel
's constructor. I still want to know what T
is in ViewModel, so when I expose Model
to the View
I know the datatype of Model
's buried Value
property. The class for ViewModel ends up looking like the following:
class ViewModel<T>
{
private Model<T> _model;
public ViewModel(Model<T> model) { ....blah.... }
public T ModelsValue {get; set; }
}
This works fine, but is limited. So now I need to expose a collection of IModels
with varying Ts
to my View
, so I'm trying to set up an ObservableCollection
of new ViewModel<T>s
to a changing list of IModels
. The problem is, I can't figure out how to get T
from Model<T>
from IModel
to construct ViewModel<T>(Model<T>)
at runtime.
In the VS2010 debugger I can mouseover any IModel
object and see its full Model<int>
for example at runtime so I know the data is in there.
Any ideas?
The alternative would be to have an interface
IModelValue
that would expose T fromModel<T>
. Then your ViewModel class would look like:C# generics won't allow generic type as type parameter:
Above is not only illegal in C#, but also makes no sense because it would break static type constraints.
I'm guessing what you really are trying to do is:
than you need some kind of factory that would produce IMyViewModel instances based on IModel runtime type:
thus, having a
you can get
Here's what I'm using for view model collections:
Preface:
Your view model objects can be weakly typed. Give
IModel
a propertyobject Value {get;}
and expose that in aModelViewModel : ViewModel<IModel>
that you use for allIModel
objects (see myViewModel<T>
implementation below). If you have various combinations ofObservableCollection<IModel>
,ICollection<Model<T>>
, etc., the framework shown here is a lifesaver. If you still need generic view model, you can derive aModelViewModel<T> : ModelViewModel
that takes aModel<T>
in its constructor. The logic to create the appropriate type would go in the converter passed toViewModelCollection.Create
below. Do be warned that this design will impose a performance penalty.Example usage:
Benefits:
INotifyCollectionChanged
if the underlying model collection implementsINotifyCollectionChanged
.Overview of the classes (full implementations linked to github):
ViewModel<TModel>
: Base class for my view model classes. Exposes aModel
property that I use in the view model's backing code.ObservableViewModelCollection<TViewModel, TModel>
: Lazy (actually not currently, but definitely should be), observable mapping from a model to a view model. ImplementsINotifyCollectionChanged
.ViewModelCollection<TViewModel, TModel>
: Lazy mapping from a collection of TModel to a collection ofTViewModel
.ViewModelCollection
: Static helper - returns anICollection<TViewModel>
, usingObservableViewModelCollection<TViewModel, TModel>
when the source collection implementsINotifyCollectionChanged
, otherwise usingViewModelCollection<TViewModel, TModel>
.A few extra types that might be useful for your view model collections:
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).ConcatCollection
ConcatCollection<T>
ObservableConcatCollection<T>
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.As a side note, when you said:
You aren't following MVVM conventions, for whatever that's worth. In MVVM, the model itself should never be exposed to the view.
That being said, you can expose the type of
T
in this way.If that suits your purposes.