Silverlight and ViewModels and ECO and Model Driven Development
…and a few other things like xaml design time binding support.
To get any of data that the model represent into a silverlight UI you must have a Silverlight project and a silverlight model and a silverlight ecospace – we have not yet extended the Wizard to handle Silverlight projects so if you want to get started right away I suggest you do so by extending the sample named SLDemo20100730 in the Demos folder of the latest ECO build.
There is not anything special about a silverlight model or ecospace – but they do reference other assemblies – like Eco.Handles.SL instead of Eco.Handles.
Suppose you have this model:
Then we can go like this:
To get this data displayed we can of course be very naive:
But let us move on with databind:
With the following XAML:
Gives us this output:
The “Doing it twice just to prove databind” reference in the code and image above is just a convenient way to ensure that the value is applied and propagated to subscribers of that value – since if I change the value in one place it should update in the other control and vice versa; if everything works that is.
And to bind to a collection of some sort:
Some xaml like this is needed for the display of the collection:
and we get this output:
As soon as the UI requires the data to be mangled/massaged/transformed or what you may call it, you quickly run into trouble with the strategy to bind straight to the domain objects. The “trouble” can be dealt with by use of derived properties and derived associations in the Model - and this is a good solution but not perfect.
The reason why I think it is not perfect is that it moves concerns of the presentation (the need for transformation) into the model – and indeed this might be a non issue and even desired if multiple UI’s has the very same need. But there will be times when you find yourself trying to transform the presentation of data in a way that does not quite seem generic enough for making it into the main model.
You can also easily find cases when the UI wants to filter some association based on a transient setting provided in the display – like “Only show orders not sent by this date” – in this case the user has been given an opportunity to provide a date and you most certainly do not want to have that filter date in the model – but you need it to define a derived association to get to the data.
Further needs will become clear when you deal with tuples of data – read more about tuples in this post.
Xaml Bindings has a Converter mechanism built in that can be useful from time to time but I does require code and references to that code so it is not my favorite in dealing with these issues. It is however essential when doing things like type conversions between a byte array and an image etc.
Enough with dwelling on the problems – let us look at the solution. The perfect solution, in my opinion, is to allow for a transform-area/rendering-area between the UI and domain model so that you can clearly decouple the two.
This is what we call a ViewModel - a ViewModel is a transformation of a part of the domain model where new attributes and associations are formed as transformations from original ones in the domain model with the sole intention to be data easily displayed by a UI.
Defining a ViewModel is very easy and I do recommend everyone to use them. ECO allows for both standard ViewModels that only focus one data transformation/mangling, but also the ViewModels with UI-hints that will help you to quickly build up standard user interfaces. For Silverlight I have not started on the latter kind with UI hints, but I will get on it right after this.
Challenges with Silverlight
Silverlight does not have support for some of the core things that we previously have built ECO-Handles on. ECO-Handles have been around since very early days and are a predecessor of ViewModels but also used internally by the different ViewModel implementations. What they do is to provide a mangling/transformation area just like ViewModels do.
The main difference between Handles and ViewModels is that Handles are normally placed on a form very close to the UI control that has need for data. And that it usually took many handles (expressionhandles typically) to get one form ready for release. The down side of this approach was that the application got a lot of tiny transformations (one per Handle-column) scattered around the application forms. Something one needed to be aware of when changing the model and thus potentially breaking existing scattered transformations. This was all according to the patterns that Windows forms and ASP.NET was built around – and I guess it emerged from the constant use of datasets some ten years ago.
The ViewModel address these challenges by holding on to a collection of transformations of all or at least several of the transformations needed for a whole UI (form/UserControl), and keeping this at model/application level rather than at the forms level. This enables us to provide a static check of all these transformations to verify that they still are valid (right click the model surface, Extras, Show model errors). Since the ViewModel also holds a straight forward way to define associations between ViewModelClasses one can get a better overview of what one wants to achieve with the ViewModel. To be fair I must state that Handles also had the ability to define derived associations – Nestings. But the ViewModels make the Nesting concept less cryptic.
Years ago I wrote a post on ECO where I added this “Note to self: write a property editor so that you can actually understand this” – With “this” I meant the Nestings in the Handles – so now I have come full circle on that subject. Good for me.
But as I said in the beginning the Handles got impaired by meeting Mr. Silverlight – Since Silverlight does not provide the ICustomTypeDescriptor that was core to the RenderedTuple objects that made up the “Objects” or “Rows” of the Handles – we needed to do something different.
As .net4 and Silverlight4 both provide the DynamicObject I thought that it would be a no-brainer to replace the backend of the RenderedTuple descriptor. But as it turned out the DynamicObject does not work when it comes to Binding in Silverlight– the one thing we needed it for.
What does however work in both Silverlight and WPF is Binding to Dictionaries. So I created a new kind of handle based on Dictionaries. The class is called Eco.ViewModel.Runtime.VMClass.
So having this ViewModel:
…you can use this in Silverlight (or WPF) like this:
and the Xaml that goes with it shows how to formulate the Bindings towards the Dictionaries:
The Binding-expressions need to have the “” –square brackets around the ViewModelColumn names – this is the syntax of the xaml binding expression language to get into the dictionary. Even if this would be acceptable it still has one major drawback – design time binding support.
In Visual Studio 2010 we have been given design time support for bindings – Thank you! But the binding support works solely on reflection and of course the VMClass-Dictionaries are empty in design time and not considered when offering design time help for bindings.
So what we did was to accept this fact (if the mountain will not come to Muhammad, Muhammad must go to the mountain ). And the solution is to read the ViewModel definition and generate code for it. A new checkbox in the ViewModelEditor – you can check it to have code generated for that ViewModel:
Then when you Update the code you will get a new file in your model assembly:
And then you can go like this in your xaml:
Please note the rather longish namespace declaration: xmlns:cgvm="clr-namespace:EcoSilverlightDemo.Model.ViewModelCodeGen_TestViewModel;assembly=EcoSilverlightDemo.Model"
I needed to create a new namespace for each ViewModel in order to avoid name clashes with the domain model.
The generated ViewModel code gave us a way to explain statically what we want to bind to. The following resource definition is also noteworthy:
Then we pick this up here:
And all of a sudden we hear choirs of angels whenever we on focus something we want to bind to:
… and it turns out that the Angels are no Angels at all but just the soft humming of our cpu fan as it uses a few clock cycles to reflect our ViewModel-generated-code in order to give us detailed information about the available bindings. Lovely!
All we need to do in runtime is to hook up that ViewModel from the resource with an actual object and ecospace: