Brendan Enrick

Daily Software Development

Wire up your ViewModels using a Service Locator

No MVVM solution is complete without having the DataContext bound to a ViewModel, but this wouldn’t be a fun development community if there were not some disagreement on the specifics of how to achieve certain goals. I will be recommending how I like to wire up ViewModels. There are other ways of doing this, but I will explain some of the reasons I use this method.

You can start by building a View that needs to have certain traits in its ViewModel and then create a well-tested ViewModel separately. This ViewModel should have all of the properties and data required by the View. Make sure you also have any commands or other functionality the View will require. It is then your job to make the connection between these two objects. The way I like doing this is by using a Service Locator to give my View the ViewModel it needs. This also gives me a good centralized location where I can make sure that my ViewModels are wired up the way I need them to be.

To create our service model we are going to need to create a class which has methods returning the ViewModels we are using in our Views. We should have one getter per ViewModel to be requested. I tend to use names matching the name of the ViewModel for the getters. The service locator will look a bit like this when you’re done. (You can also use an IoC container in the service locator, which is what I do in all of my production code. In that case you would just use the IoC container rather than instantiating the object as is done in this example.)

Code Listing 1 – The Service Locator:

public class ServiceLocator
public AwesomeViewModel AwesomeViewModel
get { return new AwesomeViewModel(); }

Notice that I can pass in any parameters needed for the ViewModel constructor so my ViewModel can depend on abstractions. The service locator can be more complicated than this if other work needs to be done to create these ViewModels. An example of such a situation is if I have shared dependencies or I am using an IoC container to create my objects.

Now that we have our code written to get us our ViewModel object we need to make this class available to all of our Views. This can be achieved by creating an instance of one of these as a static resource in our App.xaml file. Static resources defined here are easily accessible.

Code Listing 2 – Declaring the Service Locator as a Resource in App.xaml:

<Application x:Class="Awesome.App"
<Awesome:ServiceLocator x:Key="SvcLoc" />

The key that we have assigned to this resource is how we will reference it when we access it later. In other parts of our code we will just specify in our bindings that we are accessing this static resource and calling its properties to get the data that we need. In fact this is exactly how we can get our ViewModel into our View. When we bind our DataContext we will tell it that our source is going to be this ServiceLocator instance and that we are binding our DataContext to a specified path, which is a property of the ServiceLocator.

The binding can be done either of these two ways. I don’t really prefer one or the other. These are effectively the same things, so it really comes down to preference.

Code Listing 3 – Binding the DataContext to the ServiceLocator:

<Binding Path="AwesomeViewModel"
Source="{StaticResource SvcLoc}"/>

Code Listing 4 – Binding the DataContext to the ServiceLocator Inline:

DataContext="{Binding AwesomeViewModel, Source={StaticResource SvcLoc}}"

Now we can access this DataContext throughout our View by just binding to different paths on it.

I like this approach because it keeps the binding in the XAML and not in the code. It is also nice because we are able to bind easily to properties and have these properties do dependency injection for our ViewModels. The centralization of all of this ViewModel creation is also very convenient. We are able to visit this one class to make adjustments for how the entire application handles its ViewModel initialization.

Making Text Clickable in Silverlight for Windows Phone 7

I’ve seen a lot of snippets of code online where people are trying to make text clickable in Windows Phone 7, and plenty of them are using the OnMouseLeftButtonDown event to do it. Well to put this lightly, this is not the best way of handling a click in the Windows Phone 7 environment. The reason is that we have to put the “left button” down in order to scroll. The “left button” is our finger, so if we try to scroll down and press our finger on the text we will be activating the event by mistake.

In order to resolve this we need to have the click event. Well, the click event is on the Button not on the TextBlock. In this example I will be using the MVVM Light toolkit and showing how I can wire up a Click event to a command on my ViewModel.

This example is a DataTemplate being used to display a list of colors each one as a bound item in a ListBox. I will be setting the text of each item to be the name of the color and I will be handling the click event by binding it to a command on my ViewModel the command will take in the color’s ID as a parameter. Notice that since I am in a DataTemplate I have to access the ViewModel for this view by accessing my view. While in the DataTemplate my current DataContext is the Color item I am binding in the list. Read more about accessing the ViewModel from a DataTemplate.

<DataTemplate x:Key="colorListTemplate">
<TextBlock Text="{Binding Name}" FontSize="64" />
<i:EventTrigger EventName="Click">
Command="{Binding DataContext.PickColor, ElementName=TheView}"
CommandParameter="{Binding Path=ID}"/>

Notice that I set the ContentTemplate of the Button. This means that I am telling the control to not display how it would normally display and instead to display how I want it to. I do this so that I can display text as normal so that it looks like a have a regular list of items, and I am able to make this text handle the event when someone clicks on it. Keep in mind that a click and a scroll are two different operations in the Windows Phone, so non one is going to accidentally click on my item when they are trying to scroll. If I had done this with a MouseLeftButtonDown event as I’ve seen shown in the past it will cause the command to happen when someone is trying to scroll the list on the phone.
Remember that a button can look like anything in Silverlight. You have a ContentTemplate you can define for the button, so you have the power to always have a Click event. So if you need to make something clickable, make a button and put your control as the template for the button.

Accessing the ViewModel Inside a DataTemplate in Silverlight

I’ve been doing a lot of Windows Phone 7 Development, which means that I have also been doing a lot of Silveright development, so here is a tip for accessing your ViewModel when you’re in a DataTemplate.

In Silveright, DataTemplates are used when binding data to a control. For example if I want to list users I will define the DataTemplate, which will define the XAML that will be bound to for each of the users in the list. When I do this, the data context for the DataTemplate is my user and no longer the VM. I have a few options here, I can modify the user to have what I need, I can access some global class which has what I need or can access my ViewModel, or I could do what I prefer doing, which is just to name my View.

I give my name a view, and I can then create a binding which accesses an element by name instead of by using its current data context. To do this I can just name my View like this.

DataContext="{Binding BarViewModel, Source={StaticResource SL}}">


Then in my binding I can access it using the ElementName property like this. This example is wiring up a Click event using MVVM Light Toolkit’s EventToCommand.

<Custom:EventTrigger EventName="Click">
Command="{Binding DataContext.DoSomething, ElementName=TheView}"
CommandParameter="{Binding}" />

This allows me to access the commands on my ViewModel while I am using a DataTemplate. Without doing the “ElementName=TheView”, I would not easily be able to access the command from my ViewModel. I would only be able to access the commands from the User object.