.NET and me Coding dreams since 1998!

7Nov/1023

Naked MVVM–simplest possible MVVM approach

How to do MVVM in simplest possible way?

Yes, I am aware that there are at least 50 “How to do MVVM” blog posts and well known frameworks: prism, MVVM Light, Caliburn etc. Still, my friend Slobodan Pavkov convinced me to write a post and explain the approach I am personally using in my code, because (as he believes) it is so simple that it can be useful to someone -  so here I am - writing it down.
Idea is so simple that I guess it is very possible someone already blogged about it and if so please let me know so I could link that blog post here. I presume you know what MVVM already is – if not go read some of the hundreds blog posts about that and once you get it come back. My sample is done in WPF (as that is my LOB platform of choice) but it works without any changes in Silverlight too.
As all MVVM framework I had to pick a name reflecting the spirit of my “framework” and I ended with “Naked MVVM” because it reflects design principles I respect:
  1. No base classes of any kind required for framework
  2. No interfaces of any kind required for framework
  3. No attributes of any kind required for framework
  4. View first – Blend friendly & simple composition
  5. IoC enabled
  6. Works out of box as much as possible

Basic ideas behind “Naked MVVM”

Scenario

Simple MVVM framework requires simple possible problem: show in MVVM way a text box showing current date. That’s it – let’s roll.

You can download the source code of end solution here.

No base classes, interfaces and attribute

Usual implementations of MMVM I’ve seen usually have ViewModel<TView> base class and/or some form of IView view abstraction etc.
Here’s how View looks like in my approach
namespace NakedMVVM
{
    public partial class MainWindowView
    {
        public MainWindowView()
        {
            InitializeComponent();
        }
    }
}
And here is the view model containing all of the necessary requirements from my Naked MVVM framework
namespace NakedMVVM
{
    public class MainWindowViewModel
    {
    }
}
As you can tell from the code above, there are ZERO requirements from view and view model.

Wiring up the view and the view model

s you already know, the whole MVVM pattern is based on the idea that view data binds to a view model which then talks to a model.
image
A lot of samples I’ve seen, define some form of view abstraction which should enable view model to communicate with view on framework level.
All of those samples ignore one simple but VERY IMPORTANT fact – there is such abstraction already baked in .NET – FrameworkElement. Every view (user control, window etc.) inherits from the FrameworkElement and can be casted to it. The reason why I picked it up is that the framework element has a DataContext member (to bad it is not defined in some interface so I could replace FrameworkElement with it). Setting a user control data context to some value results with all of the controls in that window/user control being bounded to the same value.
To codify that thought...
namespace NakedMVVM
{
    using System.Windows;

    public class MainWindowViewModel
    {
        public MainWindowViewModel(FrameworkElement frameworkElement)
        {
            frameworkElement.DataContext = this;
        }
    }
}
The problem here is how an IoC container (one of the requirements above is to use IoC) can resolve this generic FrameworkElement constructor parameter? That question is exactly the reason why we have all of the IView and IView<T> in the MVVM blog posts. To me that well documented approach is an overkill because we create entities just to hold our infrastructure. Much better approach could be to resolve a framework element from a IoC container using a well known key. There are many way how to do that but let here illustrate it in the simplest to digest form using the ServiceLocator.
namespace NakedMVVM
{
    using System.Windows;

    using Framework;

    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            var frameworkElement = ServiceLocator.IoC.Resolve("MainView");
            frameworkElement.DataContext = this;
        }
    }
}
As you can see here, view model becomes a data context of a view without any artificial code artifacts created to enable that. If I wouldn’t have to respect my design principle #1 “No base classes of any kind required” I could extract this class to base view model class and have it applicable on all view models.
namespace NakedMVVM
{
    using System.Windows;
    using Framework;

    public class MainWindowViewModel : ViewModel
    {
    }

    public abstract class ViewModel
    {
        public ViewModel()
        {
            var frameworkElement = ServiceLocator.IoC.Resolve(this.GetType().Name.Replace("Model",""));
            frameworkElement.DataContext = this;
        }
    }
}
Too bad I am not allowed to do that so I am again deleting all of the changes in this ViewModel and restore it back to be an empty class with no base class and no wire-up code in it. To see what I do in my code you would have to be patient for a little bit more because I need to explain first may way of …

Filling the IoC container

In most MVVM samples, there is a bootstrapper class where developer enlist all of the IoC mappings. In this example it could be something like this
using System.Windows;

namespace NakedMVVM
{
    using Framework;

    public partial class App : Application
    {

        public App()
        {
            ServiceLocator.IoC.RegisterType<FrameworkElement,MainWindowView>("MainWindowView");
        }
    }
}
imageJust by looking at this single line of code, it becomes obvious that:
  • I have to do the same thing for every user control/window I have
  • I map always framework element to a user control/windows
  • The key I use to store it in IoC is the same as the name of user control/window
Every WPF/SL developer I know (including me) when doing MVVM follows the next naming convention:
  • every user control is suffixed with “View” and
  • every view model of a control is suffixed with “ViewModel”
In concrete case of the sample used in this blog post, user control is named MainWindowView and her view model class MainWindowViewModel
If we combine the 3 obvious facts given above with the naming convention we could easily come to the same idea as I did:
“Iterate all of the types in current assembly. Each one of them which name ends with “View” map as framework element using the full type name as a key. Each one of them which name ends with a “ViewModel” map as object with a full type name as a key.”
Translating that thought into a C# code class IoCBuilder in this sample was created containing this
namespace Framework
{
    using System;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;

    public static class IoCBuilder
    {
        public static void CollectViewAndViewModelMappings()
        {
            foreach (var type in Assembly.GetCallingAssembly().GetTypes())
            {
                var typeIsUserControl = type.BaseType == typeof(UserControl);
                if (typeIsUserControl)
                {
                    var typeIsView = type.Name.EndsWith("View", StringComparison.InvariantCultureIgnoreCase);
                    if (typeIsView)
                    {
                        ServiceLocator.IoC.RegisterType(typeof(FrameworkElement), type, type.FullName);
                    }
                }
                else
                {
                    var typeIsViewModel = type.Name.EndsWith("ViewModel", StringComparison.InvariantCultureIgnoreCase);
                    if (typeIsViewModel)
                    {
                        ServiceLocator.IoC.RegisterType(typeof(object), type, type.FullName);
                    }
                }
            }
        }
    }
}
Now when we have this code in place, we can replace the explicit mappings from our bootstrapper class to a framework call
namespace YAMVVM
{
    using System.Windows;
    using Framework;

    public partial class App : Application
    {
        public App()
        {
            IoCBuilder.CollectViewAndViewModelMappings();
        }
    }
}
Major upside of this approach (at least for me) is that respects design principle #6 and allows me to just add a view and a view model without thinking about IoC mappings etc.

My way of wiring up view and view model

Having in mind the content of IoC container and design principle #4 (Blendable framework) after a lot of experimenting I’ve realized that the behavior is the most suitable way of doing the wire up.
The behavior itself is quite trivial and it it reflecting the same approach as shown above in explicit wire up sample code.
namespace Framework.Behaviors
{
    using System.Windows;
    using System.Windows.Interactivity;
    using Framework;

    public class AutoWireUpViewModelBehavior : Behavior<UIElement>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            var view = (FrameworkElement)this.AssociatedObject;
            var viewModelName = string.Format("{0}Model", view.GetType().FullName);
            var viewModel = ServiceLocator.IoC.Resolve<object>(viewModelName);
            view.DataContext = viewModel;
        }
    }
}
Code is quite simple: pointer to a user control is being passed to a behavior. Following the naming convention explained above, I add the “Model”to the name of the view so I would get the specific view model key which I use to resolve view model from a container. Once resolved view model, I set to a DataContext of a user control being passed to a behavior. Same approach as the one in explicit sample, just encapsulated in the behavior.
Now when there is a framework level behavior, only thing a designer has to do to wire up a view and view model (I emphasize here again that both of them are following the #1-#3 principles and not having any base class, interface etc) is to fire up a blend and just drag&drop the AutoWireUp behavior to a control.
imageimage
Off course, for us developers executing next R# snippet and resolving namespaces is maybe more suitable solution
    <i:Interaction.Behaviors>
        <Framework:AutoWireUpViewModelBehavior />
    </i:Interaction.Behaviors>
Regardless of which way you would prefer, the end goal is achieved: view and view model are wired up on a unobtrusive way removing the need for infrastructure bloat used usually to enable that.

Putting it to work

If we run our sample, everything will work just fine (even with view and view model being completely empty) except we won’t see the current date on the screen so we can’t know for sure if it work or not, aren’t we?
Let modify the view to its final state
<Window x:Class="NakedMVVM.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Framework="clr-namespace:Framework.Behaviors;assembly=Framework"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
    <i:Interaction.Behaviors>
        <Framework:AutoWireUpViewModelBehavior />
    </i:Interaction.Behaviors>
    <Grid>
        <TextBlock Text="{Binding HeadingCaption}" />
    </Grid>
</Window>
and the view model
namespace NakedMVVM
{
    using System;
    using System.ComponentModel;

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public MainWindowViewModel()
        {
            HeadingCaption = "Yes it works on " + DateTime.UtcNow;
        }

        private string headingCaption;

        public string HeadingCaption
        {
            get { return this.headingCaption; }
            set
            {
                this.headingCaption = value;
                this.OnPropertyChanged("HeadingCaption");
            }
        }

        #region The usual INPC implementation
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion    }
    }
}
Run the app
image
See, it works Smeško
You can download the source code of end solution here.
What do you think? Have you seen this approach in whole somewhere? Does it makes sense to you or it look to you just-another-fluffy-pattern-thing?
Looking forward to hear your thoughts on my approach!
Comments (23) Trackbacks (0)
  1. Told you you should blog about it :)

    Joke aside, its an excellent post, straight to the point, keeping things simple.

    People tend to complicate MVVM and this posts shows that best solutions are the simplest ones.

    So what about other things in MVVM, any planned posts?

  2. Nice, simple solution. Another +1 for this kind of approach is barrier to entry: new WPF MVVM adopters don't have to stumble through acres of explanations to start using it effectively.

    The convention based idea was also discussed by Rob Eisenburg. Watch his "Build your own MVVM framework" presentation to see what I mean.

  3. Andre,

    with all due respect to Rob (who is top expert for sure in this area) I don't think my approach is the same due to next reasons:

    - I do view first, he did viewmodel first

    - My view models are not having any base class, no IScreen etc

    - I don't have ScreenConductor

    - He is performing explicit binding ViewModelBinder.Bind(shell, view); while I use behavior

    - etc, etc

    To be clear here: I am not foolish to claim here that my *framework* is better than his work.

    As a matter affect I claim just the opposite – my *framework* is lacking 99% of features his Mix demo had and that is a deliberate decision made on my side that after 2 years of using couple of MVVM frameworks I want to move from *frameworkability* toward naked WPF/SL and use as less possible only the REALLY necessary bits in the way which removes them from my sight as much as possible. This blog post illustrates one thing I do in that effort.

    I am not claiming at all this *naked* approach is the right thing to do, just it makes sense to me :)

  4. Excelent post!

    I have just one remark – I wouldn't use ServiceLocator anti-pattern. I would create own "IViewModelProvider" interface with single "object GetViewModel(string viewName)" method. Next step could be to add interface that translates view name to view-model name…

    Thanks for the post anyway :)

  5. Michal,

    first of all this is just a blog post and ServiceLocator is something everyone gets (even folks not used to IoC) :)

    Second, what is the purpose of adding the interfaces. Don't tell me please testability etc because we are speaking about 20 lines of code which anyone can code inspect  easilly etc.. Code is not likelly to change so "what if that change" is also not a valid argument for me.

    IMHO, you would end only with the 2 new interfaces *obfuscating* your code a bit without the real gain.

    Couple a months ago I too spoke against ServiceLocator couple of times – here's one example

    blog.vuscode.com/…/say-no-to-servicelocator.aspx

    While I blog 2+ years ago that service locator is bad because it introduces opaque dependencies

    blog.vuscode.com/…/design-for-testability-transparent-and-opaque-dependencies-part-8.aspx

    in this case it can be maybe acceptable because:

    - I am not sure how I can IoC enable behaviors

    - The ServiceLocator usage is hidden in infrastructure

    - ViewModel (subject of testing) is not having any ServiceLocator code which preserves 100% testability.

    My priorities switched in last 2 years, from being real zealot in all the good stuff "patterns", "SOLID", "*DD" etc. toward favoring simplicity of the code base enhanced with minimal amount of bells & whistles :)

    Again a think I find right for me, but not claiming at all to be the right solution for everyone :)

    Thanks you for the comment!

    Nikola

  6. Nikola,

    I think you misunderstood my comment. I meant that I've seen the convention based idea before, but I like your "as-simple-as-you-like" approach much more. I think its the kind of thing "in-the-trenches" programmers come up with that is a lot more pragmatic than what all-in-one solutions offer.

    In any case, I'll add a 'well done' too :)

  7. Nikola: Actually, I agree :-)

    I didn't realize that you are using ServiceLocator just in "AutoWireUpViewModelBehavior" class that can be called "infrastructure class". I'm using the same "pattern" in my current project.

    You wrote in the fifth law of DI: "IoC container should be explicitly used only in Bootstrapper".

    I'm not big fan of uper DDD, SOLID and TTD too, so I personally extended this law to "ServiceLocator should be explicitly used only in infrastructure classes." – I follow this law and I'm happy :)

  8. Thanks for cute article.

    One question:

    What if i have scenario when one View has two different ViewModels?, i.e. reuse of existing view.

    TNX in advance.

  9. Excellent simplicity!

    thank you for posting this.

  10. Awesome!

    I'm experimenting with WPF and MVVM and avoiding heavy frameworks which, in my experience, end up burdening me with their complexity or making it necessary for me to spend more time learning the intricacies of the framework that I do developing my code.

    I'm partway through making my own 'framework' which, it turns out, is similar to yours in many ways. I was just

    wondering how I was going to go about IoC, so I googled "simple ioc c# wpf mvvm", arrived here, and Kaching!!! hit the jackpot.

    Thanks for posting !

  11. Thank you so much for sharing this.  I've been reading bits and pieces about MVVM over the last couple years and I tried building a test app to help learn it about 5 months ago.  I got so bogged down in how to use the frameworks and all the interface junk that I decided it wasn't worth the effort (at that point in time).  

    Your method is far easier to understand and should give me a huge boost in grasping the concepts.  After a really grok MVVM using your methods I will be able to more intelligently look into the more complete frameworks, though I suspect I will also prefer simplicity like you do.

  12. Hi,

    There are some good ideas in this post. Let's start however with what I don't like if you don't mind ;)

    1) Using FrameworkElement to inject into your VM will complicate unit tests because it forces you to instantiate one. I prefer to avoid having a dependency to the view inside the view model.

    2) Your view model will need to raise the PropertyChanged event. This is in fact the minimum requirement for a view model base class (and also pretty much the only thing that ViewModelBase is doing in MVVM Light). So eventually, I think your VMBase class and mine will be very similar.

    3) Using an IOC container just to locate the VMs sounds a bit overkill to me. Now granted, this is just a blog post, and this allows CoC approach, but in my experience many first time users are scared of IOC containers. I agree that educating them on the advantages of DI/IOC is important, but at the same time I think it is important to offer an alternative which does not use those, while allowing to "upgrade" and use them if the user wants. This is what the ViewModelLocator based approach does in MVVM Light. This is a class whose single responsibility is to create and manage the VMs lifetime. If the user wants to throw a DI/IOC container in the game, it works, but this is not a requirement.

    What I like: WIring the VM to the View in a behavior sounds like a good idea. I will investigate more. One thing that is very relevant for me (and integrators like me) is to be able to do the data binding in Blend. I think that the behavior based approach will work fine, but I need to verify it.

    I also obviously like the lightness of it. In fact, if you dig, I think you will find that MVVM Light is very similar to that, a simple approach to wiring the objects and additional helpers to make work easier.

    Cheers,

    Laurent

  13. Just feeling I need to expand a little on something: What I wouldn't like is to force the usage of an external IOC container on the user. If the IOC is integrated in the framework (something like a super simple IOC container that we could wrap into MVVM Light), then this is something I have considered and still thinking about it.

    Cheers,

    Laurent

  14. Nice article, but I don't like service locator IOC container. Unity is much better for me or ninject.

  15. Slavo,

    I agree with you and that’s why I HAVE USED Unity in this blog post :)

    ServiceLocator.IoC is just a Singleton instantiating UnityContainer, nothing else.

    public static class ServiceLocator

       {

           public static readonly IUnityContainer IoC = new UnityContainer();

       }

  16. Laurent,

    first of all thank you for spending some of your VERY valuable time on reviewing the Naked MVVM

    Based on some of your comments I not sure if you had time to look at the code itself so please let me clarify couple of things mentioned in your remarks which I believe are not correct and/or accurate statements.

    (1)

    There is no FrameworkElement neither inside of the ViewModel nor elsewhere in the code. The only place where it appears is inside of the behavior itself. Testing the 4 line of that behavior doesn’t make any sense to me, and testing ViewModel (the part of MVVM triangle which needs to be unit tested) is not requiring it also. Just check the last code listing in this blog post to see how the ViewModel looks like.

    In case you still think that your statement is correct, can you please point to where in code sample we can see that inappropriate dependency

    (2)

    I agree with you that a base view model is a good practice and in fact I do have one similar to your ViewModelBase. The reason why I have omitted it from the post is to emphasize that initializing MVVM infrastructure shouldn’t rely on any functionality in any base VM class.   Base VM class should be optional (from the MVVM ‘framework’ perspective) and focused on removing code redundancy etc.  

    (3)

    I agree also with you that IoC container is scary for a lot of users still. That’s why the whole IoC code is dug deep into the single class fully encapsulated, so all a user has to do is call this single method in his App.xaml.cs

    IoCBuilder.CollectViewAndViewModelMappings();

    That’s the only thing one has to do to fill IoC container – zero knowledge and understanding of IoC required – ‘full plug & play’.

    As for rolling up my own replacement for IoC container which would be baked in the code I personally don’t like that idea due to the facts that building one is not easy and the penalty for usage of the full IoC here is drop a IoC dll in bin folder and call a IoCBuilder.CollectViewAndViewModelMappings().  There are no other requirements in how to write ViewModels etc. and no IoC knowledge required at all, so using a IoC in my approach comes very close to "free lunch” type of thing.

    In case you still think that your statement is correct and user does need to know IoC with this approach, can you please point to where in code sample we can see that?

  17. Hi!

    1) Yes you are right, I missed that. I didn't have time to check the code, and I mistakenly interpreted the first code segment in your blog post. Sorry about that. The approach makes sense.

    2) We both agree.

    3) IOC… I do see your point, but how easy is it if someone wants to use another IOC container instead of Unity (like in your example). Maybe we should take that on email… I am curious because I want to avoid forcing one IOC container rather than another.

    As you might know, I am not satisfied with the ViewModelLocator as MVVM Light has it in V3. I am looking for better solutions. I have some ideas, and this here is definitely helping.

    My email is laurent (at) galasoft (dot) ch, Can you drop me a line?

    Thanks,

    Laurent

  18. Unfortunately, this solution does not work in Blend. I have to admit, I thought it would, but for some reason Blend is not executing the Behavior and binding the View to the DataContext. If you open your solution in Blend, you will see that the TextBlock remains empty.

    And so I go back to the drawing board ;)

    Cheers,

    Laurent

  19. I am not sure why would you want to have real VM executed in blend and not something like d:DataContext (that’s what I do), but I’m sure you know why much better then I do –  I’l look at it tomorrow..

    I guess the reason could be related to the fact that the IoC mappings are missing at the moment blend construct control so I’ll try  to add lazy inti call  to IoCBuilder.CollectViewAndViewModelMappings(); in the behavior itself – guess that migh do the trick.

    Will report tomorrow what happened…

  20. Because having the real VM executed in Blend allows to work with a better abstraction of real time vs design time. You can then build services to create design time data instead of connecting to the real service. d:DataContext is useful in certain situations, but in my experience it is more difficult to understand than using the real VM and injecting different services at design time. Also, this design time data can be used at test time, so you get a mock for free. I find that using the same injection mechanism at runtime, design time and test time is the most elegant solution to this problem.

    Also, there is no support in Blend to add d:DataContext. This has to be done in XAML. This doesn't sound like a huge deal, but when you work with designers and try to initiate them to Blend, you try to avoid having to do anything in XAML. Note however that if this is really the best solution, why not, but I have the feeling that there are other ways. This is why I am still working on that and trying to improve the ViewModelLocator.

    The weird thing with the solution you proposed is that the behavior was not executed at all in Blend. This is unusual. I was busy with something else this weekend, but I will definitely dig in deeper. If the behavior was working, it would be a good solution I think. That said, I worked on implementing the super simple IOC container we talked about, and made good progress. I see a lot of value into that. OK it's not really an IOC container, and as we discussed, I think it will be rather not used outside of its primary purpose to create and locate VMs. But it is small, unobtrusive and does the job.

    Cheers,

    Laurent

  21. Very nice post…. Learned a naked approach to build MVVM.

    Thanks you…..

  22. Firstly.. Thanks for this wonderful post… It is really very informative at the same time being precise…

    One point i want to make is: Can't we make the choice about the type of Container configurable… !!!

    Thanks!!!

  23. Damn it, Andre Luus, I was going to try to seem smart by linking to Rob Eisenberg’s talk and you got there first. At least I get to point out that you mispelled his name :-P


Leave a comment

No trackbacks yet.