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

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