Silverlight Blendability with MVVM

This post is to summarise my investigations on how to wire up the View in Silverlight with the ViewModel using the MVVM pattern, and still have Blendability – the name given to being able to see test data in your Blend or Cider XAML view at design time.

There are many different approaches seen in various MVVM samples and videos. Having been confused by all the different approaches I decided to boil down the essentials into this post.

Brief Outline

The MVVM pattern separates the View from the form behaviour and data interaction. This post won’t discuss the ViewModel approach – if you are not familiar with MVVM you can check out these resources:

Instead I want to look at the way in which a ViewModel is connected or wired into the application and into the view.

Part 1 – Data Source Abstraction

We could just create a ViewModel that uses the WebService to get the data, and bind this directly to our View.

View –> ViewModel –> WebService (for data) –> Model

This approach has two problems:

  • It prevents us from unit testing the ViewModel code. Unless the WebService runs somewhere and can be accessed from the unit test code [very tricky to do!] you cannot run a unit test on a ViewModel.
  • The ViewModel would not work at design time, since the View isn’t running in a browser context, so isn’t able to call the webservice. We would have no Blendability.

So we want an MVVM technique that will support runtime, design-time and unit-test data sources. The solution to this is to introduce an abstraction layer using either an interface or base class that defines the methods used to retrieve the data, e.g. GetCustomers, etc., but it does not actually have the implementation.

I will assume here we define an interface but the base class approach is just as good: all you need is something that is interchangeable for live/design/test.

 

Part 2 – Data Source Selection

Having abstracted the data source in the ViewModel we now have the system:

View –> ViewModel –> AbstractDataSourceInterface –> Model

So this is much better,:we now have a ViewModel that doesn’t go directly to a data source, but has an abstract interface for getting the data.

The interface is a bit complicated. We can’t have a simple GetCustomers() method that returns a list of customers – we have to support the asynchronous nature of webservice calls and Silverlight calls to such services have to be asynchronous.

This is where the new C#/VB Async CTP comes to our rescue. We can actually code a method in a single call which returns the data, e.g.

public Task<List<Customer>> GetCustomers()
{ /* code here */ }

So the next problem is how to select the data source? The simplest solution is to provide a data source in the constructor. Let’s say ICustomerService is our data interface:

public class CustomerViewModel
{
public CustomerViewModel(ICustomerService service) {…}

This looks great. One small issue: we cannot reference the CustomerViewModel directly as a static resource in Silverlight as it would need a parameterless constructor.

There are two ways around this.

One is to also create a parameterless constructor. This would have to check whether the code was running in the designer or in live, and setting the data source. This means that the constructor that takes a data source would only be used for the unit test case.

Although this technique works it may cause problems: firstly you’ve now limited the control to operate with only two possible data sources (live or design). In the majority of cases this is probably not an issue, but it is worth knowing about.

Approach two is to have a factory or static method that instantiates the ViewModel for us. Some people prefer to use IoC or MEF for such. You can read more on these in the next section.

Part 3 – Linking the View to the ViewModel

The final step, having defined the ViewModel is to bind it to the view. This means creating an instance of the ViewModel (or getting an existing instance, when a ViewModel is shared).

Many examples of data binding set the DataContext in code. This is fine and will work when the code is executed. In design mode however the code behind the form does not get executed so it would not bind. Hence, no design-time data.

To get design time data, there are two main techniques.

A) Static Resource Method

A simple way to set the data context in a View is to use a static resource in the page. This approach will work only if the ViewModel has a parameterless constructor, since the designer can only create static resources where this is the case.

There are three steps to doing this

1. Import the namespace containing the ViewModel in the control header so you can access it

xmlns:local="clr-namespace:MyApplication.CustomerViewModels"

2. Create a static resource of the ViewModel (usually in the UserControl resources section). The Key is how it’s referred to in the control.

<UserControl.Resources>
<local:CustomerViewModel x:Key="vm" />
</UserControl.Resources>

3. Set the DataContext using a binding, with the Source being the StaticResource. Often the ViewModel is the DataContext for the LayoutRoot control.

<Grid x:Name="LayoutRoot" Background="White" DataContext="{BindingSource={StaticResource vm}}">

The only drawback to doing this is that the ViewModel cannot be shared or retained in memory, since a new one is created each time a control instance is created.

B) Service Locator Method

The second approach is to have a service locator or factory class which creates and manages instances. John Papa has a good article on how these work.

Rather than creating an instance itself, the locator method returns the instance, which is created once and then shared.

The simplest way to implement such a pattern is to create a static resource in the application (rather than the control) for the ViewModelLocator, and then use a property of the ViewModelLocator as

Advertisements

Silverlight DataContext and Binding

The data binding is Silverlight is exceptionally powerful. But with great power comes great complexity, and it can be difficult to understand how DataContext, Binding, and all the variations of syntax work and fit together.

This is my handy one-stop-reference based on my own reading and experimentation.

DataContext

DataContext is a property of the FrameworkElement class, and since this is a base of the Control class it means all Silverlight controls have a DataContext.

The DataContext is set for all of the child controls within that control, so once you set the DataContext for a container, you can refer to it within the child controls using the {Binding …} syntax [more on that below].

Setting DataContext

DataContext can be set in code (in the constructor of a View, for example):

    Public Sub New()
        InitializeComponent()
        'Set the datacontext Me.DataContext = New MainPageViewModel End Sub 

Why Not?

This works fine at runtime, but won’t work within the design time model if you want to see Design Time Data in Blend or Visual Studio.

You can set the DataContext in design time if you use the d:DesignInstance and d:DesignData options.

One alternative way is to set the DataContext in the XAML. This can be done by:

  1. setting the namespace in the user control namespaces:
  2. adding a resources section
  3. setting the LayoutRoot element’s datacontext to the ViewModel.
    Look at my other post on this topic.

{Binding}

In ASP.NET you have to bind data values with the fairly clumsy syntax <%# Eval(“property”) %> and <%# Bind(“property”) %>. This is basically ‘convert my value to a string and embed in the HTML’. This makes sense since HTML is just text – there are no native types except HTML, which is text.

In Silverlight, most of the properties of XAML controls are Dependency Properties.

Dependency properties mean almost any property can be bound to a source of data. Instead of XAML with a static binding, e.g. Text=”Hello” we using the Binding syntax.

For example if our DataContext class has a property of Name, we can say

Text=”{Binding Name}”

Note that this is actually a shorthand for the syntax

Text=”{Binding Path=Name}”

However, you are not limited to a simple property expression – the binding can be a path.

Let’s say the current DataContext is a ViewModel with a property called CurrentCustomer, which is a Customer type. This has as property LastOrder of type Order, and the Order class has a property TotalValue. We can refer to the total value directly:

Text=”{Binding CurrentCustomer.LastOrder.TotalValue}”

 

Binding Errors

Bindings are text names and are not normally resolved at design or compile time, so it’s quite easy to get them wrong:

Text=”{Binding Nane}”

You might expect an error at runtime – but in Silverlight 4 the binding fails silently(and unless you have SL5 then it’s hard to debug!). Instead the binding is a null value and ignored.

One way to help prevent binding errors is to use Design Time Data – this is where the designer (VS or Blend) creates dummy data within the view so the fields are populated. See the Design-Time Data section later on. This is incredibly helpful in getting designs right without having to continually build and run the application.

Note that binding is case sensitive so with a property TotalValue {Binding totalValue} is not found, whereas {Binding TotalValue} is.

Hint: open the immediate window in Visual Studio when opening a Silverlight control – you’ll see binding exceptions listed.

Formatting

In the example above TotalValue might be a Decimal value: let’s say it is 1234.56. However we are binding the TotalValue directly so the resulting output would be 1234.56. There is a StringFormat option to formatting. The only thing you have to remember is that you have to escape the { } values if used:

Text=”{Binding CurrentCustomer.LastOrder.TotalValue, StringFormat=Total:\{0:c\}}”

If you try this outside the US and get $1,234.56 instead of your own currency, you may want to set the application locale. Also note that if there are no complex formatting options, you can just use a simple format, e.g.

Text=”{Binding CurrentCustomer.LastOrder.TotalValue, StringFormat=c}”

An interesting comparison with ASP.NET here – often showing a display format for editing values in textboxes meant they would fail. With Silverlight the conversion to a currency is a two-way process.

Culture Settings

In ASP.NET the culture settings defines how format strings such as {0:d} and {0:c} are formatted. Usually the CurrentCulture or CurrentUICulture settings are used. In Silverlight this is not the case: the key setting is XML Language which is a property of the FrameworkElement base class. You can read more about this in Tim Heuer’s blog post.

The best approach may be to set the root application control or view to copy or set the Language property of the base to use either the browser setting or hard-code a predefined setting.

Modes

Binding allows you to optionally specify the Mode for binding: the values are OneTime, OneWay and TwoWay.

OneTime sets the value once and will not update it if the data source changes. This might be used if you wanted to set say, a field “Original price” just before an edit, and that won’t update when the user edits the price of the object.

OneWay is the default value: the value can be set, and will update if the source changes and supports the INotifyPropertyChanged method. If a TextBox has the text property set with a Binding that is OneWay, then changing the text will not update the DataContext.

TwoWay provides a read-write setting so that changes by the user to the value will update the underlying data object.

Conversion:

Sometimes binding requires conversion. For example, I might have a list box of items, and a Delete button next to it, that deletes the selected item. However, when there isn’t a selected item in the list box, the correct behaviour should be for the Delete button to be disabled.

In the old VB days you’d handle the SelectionChanged event and have the code-behind have something like Button1.Enabled = (ListBox1.SelectedItems.Count >0) to set the button state.

However this is Silverlight so we’re better than that and we want to avoid code-behind in the View if possible, so we should bind the IsEnabled property value to something on the listbox. The problem here is that IsEnabled is a Boolean, and there are no properties on ListBox1 that return a Boolean for the selection. The best we have is ListBox1.SelectedItems.Count – but we can’t enter an expression for binding like Path=(ListBox1.SelectedItems.Count > 0).

This is where converters come in: we can create a converter that takes an integer value and returns a boolean. Here we want to convert any value over zero as a “true” to make the button enabled.

[not quite finished yet .. example, binding , tests]

At last, I’ve seen the light.. and it’s Silver

This is just some random notes on ASP.NET vs. Silverlight business applications.

One of our major problems is getting reusability of components.The n-tier architecture is great at separating concerns – problem is that works against a modular application where we want to add functionality independently and discretely.

To explain: we have our core application (in this case, called Anvil). It’s got a database and some business logic and a front end in ASP.NET. So far so good – except we need to support “pluggable” products into this application where the functionality is outside of the existing application:

Element Main application Product X
Data layer SQL server table Reuses this (XML data for additional attributes)
Business Layer IProduct interface Product implementation and business logic
Presentation ASP.NET website and controls ?

There isn’t an issue in creating a product DLL which can link to the parent application using an Interface (in this case let’s say IProduct).

The problem arises when we hit the presentation layer (in this case it’s currently ASP.NET). We can’t embed ASCX controls in a DLL* so this means we have to put part of the Product X functionality in the website. That immediately compromises the logical design.

We have to put the controls into the website in the main application. This means I might as well forget modularity and move the code for ProductX into the main application so it’s monolithic again.

If this were a Windows Forms application this would be easy: I’d create controls in the ProductX.DLL and the ‘ProductX’ instance would know how to display itself. I could combine the business logic (ProductX class and methods) along with a pre-packaged set of UIs to handle them.

Unfortunately this is a distributed application delivered via the web so Windows Forms is not an option! It was for this reason I’d been looking at two alternatives: MVC (specifically, Razor) and Silverlight.

MVC

MVC can improve matters quite a lot by making it possible to embed Razor controls in the DLL for product X. This does mean I can get away from putting the logic into the existing web.

However when experimenting with MVC routing seems rather constrained, and getting MVC to compile and use Razor views seemed rather like a hack than a natural, supported approach.

Client functionality and behaviour (showing, hiding, selecting etc.) then has to be written in JavaScript – not my favourite language.

Yes there are lots of cool controls and libraries like jQuery etc. to help, but the fundamental issue remains: the medium (html/web) isn’t really designed for this. HTML5 is a step in the right direction, but but this gets us to about the level of functionality that Visual Basic had in the 1990s, and I’d have to require clients to upgrade browsers to run my application. So it’s not a solution that works right now.

Silverlight

The other option I’d been looking at for so long was using Silverlight. The downside to Silverlight is that I’d be excluding a small segment of the audience – mainly iPads and Linux users. As I this is a vanishingly small percentage of my customer base it was something I could overlook.

The key advantage of Silverlight is the richness of the client. So many times in ASP.NET (or any other Html-based application) you’re spending a lot of time fighting the nature of the medium. Date control? Input validation? Cross-site scripting attack? Lack of state?

Html is great at presenting data, but as an application platform it really, really sucks.

Silverlight has the added bonus of the overlap to WP7 phones so there could be a lot of reusability in WP7 phone apps too – although not an immediate benefit to us.

So now we have to put together some proof-of-concept mock-ups and start learning what we need to know!


EDIT

Update April 2012: We’ve ceased new development on Silverlight given Microsoft’s lack of clarity on Silverlight’s future.

That uncertainty, plus the increasing importance of mobile and tablets means we now have to include these in our plans. That rules out Silverlight, and leaves just HTML.

However, I’ve got upto speed on MVC now and that, plus excellent libraries like KnockoutJS mean we can have the responsive UI we want without going down the RIA path.


* yes it is possible to embed ASCX files in DLLs but you still have to copy the source into the web application – hardly an elegant, modular solution – it’s just a hack with messy manual workarounds