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]

Advertisements

2 thoughts on “Silverlight DataContext and Binding

  1. This is a great refresher of all these topics. One thing I am curious about, which you mention above is the DesignData. Where can I find more straight-forward information about leveraging that?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s