MVVM Pattern – How to Separate the ViewModel from the Model in C#

cmvvmseparation-of-concernsservice-locatorwpf

In a wpf application, a Model object is created either from scratch or deserialized from some .xml file. To create a connection to the ViewModel, the following method (on the Model!) is used by the application:

class Model
{
    public override UserControl View
    {
        get
        {
            if (_view == null)
            {
                ViewModel viewModel = new ViewModel(this);
                _view = new View();
                _view.DataContext = viewModel;
            }
            return _view;
        }
    }
}

So far, so not mvvm. The Model should not know (=have a direct reference to) the ViewModel, let alone the View.

mvvm diagram
(source: s-msft.com)

Breaking the pattern this way served as a convenient shortcut, but is starting to take a toll. I'd like to get rid of this method to separate the concerns properly as intended by the pattern.

But how would I do that? The functionality of the method in itself looks alright mmvm-wise. If I'd take it out of Model and place it in the application, it looks like proper mvvm-ish code that wires up the components:

ViewModel viewModel = new ViewModel(new Model);
_view = new View();
_view.DataContext = viewModel;

But I cannot do that, because I do not know what Model class I'm dealing with, when looking at the problem from the application point of view, because any one of several Model classes might get instantiated or deserialized. In some sense, the Model knows best what ViewModel to use (hence the current implementation), but this is exactly the dependency that I'm trying to avoid.

How to build the parts of the mvvm pattern "against the grain" of the dependencies of the pattern? That is, going from Model to View(Model)and not the other way round.

  • A simple solution might be to define a data structure in the application (e.g. a Dictionary) to associate a specific ViewModel that should be used with a specific Model, but this means maintainance when adding more classes, making mistakes doing so, etc.
  • One could also build that association with reflection introducing a strict naming scheme like every FooModel will go together with a FooModelView, which would be an improvement, but is still prone to breaking.
  • Or use some dependency injector thingy (e.g. mef) to automate the process of finding the pieces that belong together. But again, the dependencies seem to go the wrong way: The ViewModel might [Import] an IModel that the Model could then [export], but the Model (=the dependency) is created first, so I'd be looking for imports that would be satisfied with a given export and not the other way round. While such tools would help to split the concerns across even different assemblies (which is good and a goal, too), they don't solve the underlying problem that I don't know how to start this separation in the first place, which isn't their intended purpose anyway. If I swap import and export, my guess is that I'd end up with what I started with.

Are there any better solutions than building an association between the two (either by hardcoding it or reflection) in the application?


can you explain how and why each ViewModel doesn't already know the proper Model class to instantiate and the proper Model methods to call? Isn't that one of the primary reasons for having ViewModel classes in the first place?

Every ViewModel knows the proper Model class. I'm sorry if that wasn't clear from the text. In the code example, the Model is passed to the constructor of the ViewModel.
The ViewModel does not instantiate the Model object as this object might be constructed elsewhere (e.g. it could come from a deserialisation process).
That is indeed the primary reason for it to exist.

The problem is deciding what ViewModel to create, so that the Model (of a type that is decided at runtime) at hand can be passed to it.

Assuming you intend to use some form of IoC to solve this problem, couldn't you simply use the configuration of the DI container to identify the required model, or use a Service Locator?

Can you also further clarify the phrase, "Breaking the pattern this way served as a convenient shortcut, but is starting to take a toll"?

Given that the Model itself ensured that the right ViewModel (and View) would be instantiated, the returned value could be carelessly added to the screen. The correct wiring of the components happened in the method seen in the first code example. So much for the convenience of being able to "display" a Model. The toll to be paied is that Model would use and therefore reference View and ViewModel, which are classes that depend on GUI libraries, which the Model should not depend on.

or, to be blunt: Why does this console application need 5 dlls for graphical user interface components?

couldn't you simply use the configuration of the DI container to identify the required model, or use a Service Locator?

I guess the mentioned datastructure that associates ViewModel with Model is a (poor man's) Service Locator. I'm new to that pattern, but from a first glance that seems to be the case. Using the expected type of the ViewModels to build it is something I haven't thought about. (I'm thinking and not or regarding your question) As far as that approach goes, I'd take your suggestion as an answer. I was however hoping for a solution that's a little less DIY-ish. Seeing how binding does a lot of thing automatically, I'm somewhat surprised to find that going the opposite direction (that is, having a Model to begin with) requires such manual dependency management. But then maybe this is what it takes.

Best Answer

Here are my suggestions:

Suggestion 1

You could try to use extension methods in order to separate concerns and in the end, perform exactly what you need (models that know their respective viewmodels):

using System;
using System.Collections.Generic;

namespace Yay
{
    public class BaseModel
    {
        public bool CommonStuff { get; set; }
    }

    public class FromScratchModel : BaseModel
    {
        public string A { get; set; }
        public string B { get; set; }

    }

    public class DeserializedModel : BaseModel
    {
        public int C { get; set; }
        public bool D { get; set; }

    }

    public class BaseViewModel
    {
        public override string ToString()
        {
            return "Base View Model!!!!";
        }
    }

    public class ViewModel1 : BaseViewModel
    {
        public override string ToString()
        {
            return "View Model - From Scratch!!!!";
        }
    }

    public class ViewModel2 : BaseViewModel
    {
        public override string ToString()
        {
            return "View Model - Deserialized!!!!";
        }
    }

    static class Extensions
    {

        public static BaseViewModel GetViewModel(this BaseModel model)
        {
            return new BaseViewModel();
        }

        public static BaseViewModel GetViewModel(this FromScratchModel model)
        {
            return new ViewModel1();
        }

        public static BaseViewModel GetViewModel(this DeserializedModel model)
        {
            return new ViewModel2();
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            IList<BaseModel> models = 
                new List<BaseModel> { new BaseModel(), 
                                    new FromScratchModel(), 
                                    new DeserializedModel() };
            foreach (var model in models)
            {
                //Calling model.GetViewModel() will not work here; already tried (it runs, but it will return the BaseViewModel always).
                //But it's possible to call the right method resolved at runtime
                //using dynamic keyword
                BaseViewModel viewModel = Extensions.GetViewModel(model as dynamic);
                Console.WriteLine(viewModel.ToString());
            }

            Console.ReadLine();
        }
    }
}

Suggestion 2

You have different models that can arrive, that are resolved at runtime. In this option I suggest:

  • On your core project (not the UI project), for each type of your model, create a "model loader" class, that will Notify the clients about new models (eg: DeserializedModelLoader; FromScratchModelLoader)
  • On your UI, create one listener for each type of existing model (eg: DeserializedModelListener, FromScratchModelListener);
  • each listener can return a ViewModel ready to be rendered, which will be of the appropriate type, and already contain the Model received;
  • maintain a list of those listeners; for every new Model arrived, you can retrieve the appropriate ViewModel from the listener that received something.
Related Topic