Building an MVVM framework for both .Net and .Net CF

by Tom 20. May 2010 14:21

Introduction

As you might allready know, I am maintaining a .Net CF application for one of my customers. Unfortunately, the design of the app is a total disaster, and maintaining it is actually a living hell. Fortunately however, my client decided to order a complete rewrite, which I started today. This post will not contain the sourcecode (as it is a proprietary app), but rather explain the guts of the underlying architecture and some info about the design decisions used.

Maybe I will release some of the reusable components in the future under open source, but I am not quite sure yet...

 

Yet another framework ?

Actually, yes !! My main concern about this app framework is keeping it lightweight, flexible, ultraportable and easy to use. By ultraportable I mean that the app should both run on the default .Net, as well as on the Compact Framework, without recompilation.

Since no framework known to me meets my criteria, I decided to get started on yet another framework.

The main design decisions are heavily based on my previous experiences with MvcExtensions, my other framework, as well as a very inspiring and well-know lecture by Rob Eisenberg: "Build your own MVVM framework".

Service tools

I have written and implemented the following interfaces which help me in developping the app.

A simple IOC container interface that looks like this


public interface IIOC
{
  T Resolve<T>();
  T Resolve<T>(string name);
  object ResolveObject(string TypeName);
  object ResolveObject(string name,string TypeName);
}


And to register something into the container I have the following methods:


  T Register<T>(T instance);
  T Register<T>(string name,T instance);
  T Register<T>(Func<IIOC,T> factory);
  T Register<T>(string name,Func<IIOC,T> factory);

Next to this I also implemented a lightweight AutoMapper, which I use for just about everything:


public interface IMapper
{
  public void Map(object source,object destination);
}


And again, the implementation allows me to register some mappings using the following function:

    void Register<TSource,TDestination>(Action<TSource,TDestination,IMapper> map);

Next to this I also created a class called ActionResult (looks familiar, doesn't it ;) ).


{
  public object Viewmodel {get;set;}
  public ActionLink Redirect {get;set;}
  public bool Terminate {get;set;}
}

Allthough I have to say that I still have to implement the ActionLink class.

Glueing everything together

Everything you have read so far might seem awfully familiar to some people, which is a good thing imho. But having these tools available is still not the same as having an app framework, or is it ?

Actually, it is almost; my main focus is in the convention-based Model-View-ViewModel approach, which allows me to have controller actions like this:


public class MainController
{

   IMapper sMap;
   IOrderService sOrder;
   IViewModelResolver sVMResolver

   public MainController(IMapper sMap, IOrderService sOrder,IViewModelResolver sVMResolver)
   {
      this.sMap = sMap;
      this.sOrder = sOrder:
   }

   public ActionResult Index()
   {
      var vm = sVMResolver.Resolve<VMIndex>();
      sMap.Map(sOrder.GetOrders(),vm);
      return new ActionResult() { Viewmodel=vm };   
   }
}

Which should also look very familiar !!!

.... in a single form

Now, we have an ActionResult which contains a model, how do we know which form to show ??? It is quite simple : I use a convention. All my Viewmodels start with the letters "VM", and all my views (winforms usercontrols) end with the word "View".

I use a veiwmodel-first approach, i.e. based on my viewmodel, I choose which view to show. This looks like the best approach to me...

I have one Form named MainForm, which contains the following property:


object _Viewmodel;

public object Viewmodel
{
  get
  {
     return _Viewmodel;
  }
  set
  {
    if (_Viewmodel == value)
      return;
     _Viewmodel = value;    
    var t = this.Namespace+"."+_Viewmodel.GetType().Name.Substring(3)+"View";
    var vw = IOC.ResolveObject(t) as UserControl; 
    this.SuspendLayout();
    this.Controls.Clear();
    sMapper.Map(_Viewmodel,vw);
    this.Controls.Add(vw);
    foreach (var prop in _Viewmodel.GetType().GetProperties())
    {
       var ctrl = vw.Controls.Where(x=>x.Name==prop.Name).FirstOrDefault();
       if (ctrl==null) continue;
       sMapper.Map(prop.GetValue(_Viewmodel,null),ctrl));
    }
    foreach (var meth in _Viewmodel.GetType().GetMethods().Where(x=>x.Name.StartsWith("On"))
    {
        // do something similar for the methods; bind them to the corresponding actionlinks
    }
    this.ResumeLayout();
  }
}

And then my main loop will look something like this (not implemented yet):


void Run()
{
    var frm = new MainForm();
    var ar = new ActionResult() {Redirect=new Redirect<MainController>(x=>x.Index())};
    while (!ar.Terminate)
    {
       if (ar.Redirect!=null)
         ar = InvokeActionLink(ar.Redirect);
      else   
      {
         frm.Model = ar.Model;
         ar = WaitForActionResult(frm);
      }
    }
}

Conclusion

While the framework is not yet complete, this is the way I am going to implement the whole thing... If you have any suggestions or comments please do let me know what you think !!!

Bookmark and Share

About Tom

Tom Janssens op LinkedIn

Tom Janssens op twitter

Core bvba RSS

 

Tom Janssens is an independent freelance ICT consultant that has been "into computers" ever since the age of 7.

Typing source code from a book evolved into exploring the limits of coding in procedural, assembly and object-oriented languages.
As he matured in software coding, he started focussing on the problems surrounding software development, and learned that software development is usually about people and interactions first, and about technology second.

Due to his diverse track record he gained insights in a lot of aspects of the software development process. Currently his main focus is on strategic ICT advice, lean product/project development and improving the software development process and architecture.

He avoids ivory-tower-approaches by applying and verifying the applicability of the latest tech buzz in software experiments.

He is also the founder of the following LinkedIn groups:

CQRS Professional
BDD Professional
Asp.Net MVC professional

More info about Tom and his company...


Advertisement

Forget all your SCRUM -, Kanban - and other Agile and Lean certificates

Here is the only true AGILE and LEAN certificate you will ever need:

The Creative Recursive Analysis Process Certificate
(CRAP Certificate for short)

More info can be found at the official CRAP certificate website:
http://bit.ly/CRAPCertificate