Click here to Skip to main content
Click here to Skip to main content

Tagged as

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

, 20 May 2010
Rate this:
Please Sign up or sign in to vote.
This post will explain the guts of the underlying architecture and some information about the design decisions used.

Introduction

As you might already 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 source code (as it is a proprietary app), but rather explain the guts of the underlying architecture and some information 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 developing 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 Wink | ;) ).

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

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

Gluing 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tom Janssens
Founder Core bvba
Belgium Belgium
Tom Janssens, owner of Core, a software and consultancy company.
Father of two sons named Quinten & Matisse, and married to a beautiful woman named Liesbeth.
 
Blog: http://tojans.me
Github: http://github.com/ToJans
Twitter: http://twitter.com/ToJans
LinkedIn: http://www.linkedin.com/in/tomjanssens

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 20 May 2010
Article Copyright 2010 by Tom Janssens
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid