views:

261

answers:

1

Hello Stackoverflowers! :)

Today I have a special question on Silverlight (4 RC) MVVM and inheritance concepts and looking for a best practice solution... I think that i understand the basic idea and concepts behind MVVM. My Model doesn't know anything about the ViewModel as the ViewModel itself doesn't know about the View. The ViewModel knows the Model and the Views know the ViewModels.

Imagine the following basic (example) scenario (I'm trying to keep anything short and simple):

My Model contains a ProductBase class with a few basic properties, a SimpleProduct : ProductBase adding a few more Properties and ExtendedProduct : ProductBase adding another properties. According to this Model I have several ViewModels, most essential SimpleProductViewModel : ViewModelBase and ExtendedProductViewModel : ViewModelBase. Last but not least, according Views SimpleProductView and ExtendedProductView. In future, I might add many product types (and matching Views + VMs).

1. How do i know which ViewModel to create when receiving a Model collection?
After calling my data provider method, it will finally end up having a List<ProductBase>. It containts, for example, one SimpleProduct and two ExtendedProducts. How can I transform the results to an ObservableCollection<ViewModelBase> having the proper ViewModel types (one SimpleProductViewModel and two ExtendedProductViewModels) in it?

I might check for Model type and construct the ViewModel accordingly, i.e.

foreach(ProductBase currentProductBase in resultList)
    if (currentProductBase is SimpleProduct)
      viewModels.Add(
        new SimpleProductViewModel((SimpleProduct)currentProductBase));

    else if (currentProductBase is ExtendedProduct)
      viewModels.Add(
        new ExtendedProductViewModels((ExtendedProduct)currentProductBase));
    ...
}

...but I consider this very bad practice as this code doesn't follow the object oriented design. The other way round, providing abstract Factory methods would reduce the code to:

foreach(ProductBase currentProductBase in resultList)
    viewModels.Add(currentProductBase.CreateViewModel())

and would be perfectly extensible but since the Model doesn't know the ViewModels, that's not possible. I might bring interfaces into game here, but I haven't seen such approach proven yet.

2. How do i know which View to display when selecting a ViewModel?
This is pretty the same problem, but on a higher level. Ended up finally having the desired ObservableCollection<ViewModelBase> collection would require the main view to choose a matching View for the ViewModel.

In WPF, there is a DataTemplate concept which can supply a View upon a defined DataType. Unfortunately, this doesn't work in Silverlight and the only replacement I've found was the ResourceSelector of the SLExtensions toolkit which is buggy and not satisfying.

Beside that, all problems from Question 1 apply as well.

Do you have some hints or even a solution for the problems I describe, which you hopefully can understand from my explanation?

Thank you in advance!

Thomas

+2  A: 

I do this kind of thing to make MVVM strongly-typed.

I define some basic interfaces

public interface IModel
{
}

public interface IViewModel
{
}

public interface IViewModel<M> : IViewModel
    where M : IModel
{
    void Bind(M model);
}

public interface IView
{
}

public interface IView<VM> : IView
    where VM : IViewModel
{
    void Bind(VM viewModel);
}

This provides the basic relationships between my models, model views & views.

I create abstract implementations for IModel and the generic IViewModel<> & IView<> interfaces.

public abstract class ModelBase : IModel
{
}

public abstract class ViewModelBase<M> : IViewModel<M>
    where M : IModel
{
    public abstract void Bind(M model);
}

public abstract class ViewBase<VM> : IView<VM>
where VM : IViewModel
{
    public abstract void Bind(VM viewModel);
}

I then use these to define the actual concrete objects - with interfaces first of course.

public interface IPersonModel : IModel
{
}

public interface IPersonViewModel : IViewModel<IPersonModel>
{
}

public interface IPersonView : IView<IPersonViewModel>
{
}

Note how the inheritance of the interface locks in the type relationships.

Now the concrete classes can be defined.

public class PersonModel : ModelBase, IPersonModel
{
}

public class PersonViewModel : ViewModelBase<IPersonModel>, IPersonViewModel
{
    public override void Bind(IPersonModel model)
    {
        throw new NotImplementedException();
    }
}

public class PersonView : ViewBase<IPersonViewModel>, IPersonView
{
    public override void Bind(IPersonViewModel viewModel)
    {
        throw new NotImplementedException();
    }
}

So given a model I can look for an object that implements the IViewModel<M> for that model & given a view model I can look for the IView<VM> for that view model.

Dependency injection frameworks can be used here to do the look ups.

I hope this helps.

Enigmativity
Enigmativity, thank you very much for your response, I found this MVVM based Interface implementation very useful. But at the end, for me still a gap exists... what would a basic implementation of "Bind(IPersonModel model)" look, and can you provide more information on looking up interfaces' concrete classes? (further reading link?) Thank you very much for the support!
moonground.de
(Very soon I'll be able up to upvote I'm still new to SO and earning first reputation is hard ;-))
moonground.de
The implementation of `Bind(IPersonModel model)` will store the model in a field to use as the backing variable for model-related properties on the view model and will also set up any event handlers required. For the view it will also be used to set up the actual binding to the view model.
Enigmativity