Cross-Training in Silverlight & Flex–Data Binding

More Cross-Training in SIlverlight and Flex

Shout it

One of the most powerful and compelling features of RIA frameworks like Silverlight and Flex is data binding.  Data binding is where you declaratively state that a property in the view is “bound” to data in your model (or presentation behavior layer).  This means that when the model data changes, the UI is updated.  Conversely, when a user sets something in the UI layer, the model is then updated.

This capability greatly increases the ability to write features by reducing the amount of value management code the developer has to write.  Data binding makes patterns like MVVM and Presentation Model possible because it eliminates boiler-plate code that is often found in other patterns like Model-View-Presenter.  Data binding, in my opinion, is one of the features of modern application stacks that sets them apart from their ancestors.

In this article, I will discuss the different ways you might want to use data binding in Silverlight and Flex.  I will describe how the approaches differ.  You will see how similar they are as well.  All of these examples can be found on my BitBucket site where all of my “Cross-Training” examples can be found.

Data Binding in Silverlight

Data binding in Silverlight is purely declarative (as opposed to Flex, which is expression-based).  For any given property in the visual tree, the developer can use a binding syntax to declaratively state how to bind.  Silverlight conventions have you set a “data context” for a visual element in which the binding declaration works against.  These bindings can be created imperatively in code, but they are typically defined in XAML unless there is a more dynamic reason to do it differently.

Data Contexts

You define data contexts for a visual tree.  When the data context is set, it remains in scope for all descendants in the visual tree unless is is set again.  Data contexts can be set in XAML or in code and they can be any object.  Here is an example of setting a data context that will be used for all of the examples to come:

<UserControl.Resources>
    <local:DataModel x:Name="dataModel" SimpleText="default">
        <local:DataModel.Person>
            <local:Person>
                <local:Person.FullName>
                    <local:PersonName First="Brian" Last="Genisio" />
                </local:Person.FullName>
            </local:Person>
        </local:DataModel.Person>
    </local:DataModel>
</UserControl.Resources>

<StackPanel DataContext="{StaticResource dataModel}">
</StackPanel>

All of the examples in this post will be inside the StackPanel so they will inherit the data context from their visual parent.  There are certainly other ways of setting the DataContext but this is how we will do it for this post.

Basic Example

Now that we have seen an example of setting the data context, lets bind to the SimpleText property in the data model:

<TextBlock Text="{Binding SimpleText}" />

By using this simple binding syntax, the text block in the UI will show the value of SimpleText.  In this case, the UI will show “default”.

Change Notification

Displaying data is great and very often, this is all you need.  Often, though, you need to update the UI when the property changes.  It becomes the data object’s responsibility to notify the listener (the UI in this case) of the change so it knows to modify the text.

Typically, this is done with the INotifyPropertyChanged interface.  The interface defines one event – PropertyChanged – which sends the name of the property that changed.  The interface is not specific to the UI layer but the UI layer knows how to process the event through the binding you created in the XAML. 

This is how you implement INotifyPropertyChanged in the DataModel class:

public class DataModel : INotifyPropertyChanged
{
    private string _simpleText = "first";
    public string SimpleText
    {
        get { return _simpleText; }
        set
        {
            if (_simpleText == value)
                return;

            _simpleText = value;
            OnPropertyChanged("SimpleText");
        }
    }

    protected void OnPropertyChanged(string property)
    {
        var handlers = PropertyChanged;
        if (handlers != null)
            handlers(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

The first part of this class defines the notifiable property using a common pattern.  It uses a private backing store (_simpleText) and delegates to it in the property getter and setter.  The setter checks to make sure the value has changed so it doesn’t send an event when nothing changed.  It then sets the backing store and fires an event saying “SimpleText” has changed.

The second part of this code implements the event that was defined in the INotifyPropertyChanged interface.  It uses a very common event pattern of using a protected OnPropertyChanged method.  Inside, it makes a copy of the handlers to avoid any changes that may happen while looping through the handlers.  It then calls the handlers if they exist.  It is very common to push the second part of this class into a common Notifiable class.

Now that the DataModel can notify the UI of changes to SimpleText, you can can set the property being changed:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding SimpleText}" />
    <Button Content="update text" Click="UpdateSimpleText" />
</StackPanel>
private void UpdateSimpleText(object sender, RoutedEventArgs e)
{
    (Resources["dataModel"] as DataModel).SimpleText = "updated";
}

In this example, the value begins with “default” just as the before.  When you press the “update text” button, the SimpleText property is modified.  Internally, the property notifies the UI of the change and user sees “updated”.

Dependency Properties

Visual elements within Silverlight use a different mechanism for property notification.  Dependency Properties are the preferred method for creating bindable properties on UI elements.  More specifically, any class that derives from DependencyObject should avoid using INotifyPropertyChanged and use Dependency Properties instead.

Dependency Properties are created imperatively in the code behind of the visual element.  Add a Dependency Property to the MainPage user control:

public static DependencyProperty LocalTextProperty =
    DependencyProperty.Register("LocalText",
        typeof(String), typeof(MainPage),
        new PropertyMetadata(""));

public string LocalText
{
    get { return GetValue(LocalTextProperty) as string; }
    set { SetValue(LocalTextProperty, value); }
}

With this property created, you can now bind to a property in my user control, instead of a data object:

<StackPanel Orientation="Horizontal">
    <TextBox Text="{Binding ElementName=root, Path=LocalText,  Mode=TwoWay}" Width="100" />
    <TextBox Text="{Binding ElementName=root, Path=LocalText}" Width="100" />
</StackPanel>

There are a few things to notice here:

  • ElementName refers to the root control, which is of type MainPage.  This ignores the inherited data context.
  • In the first TextBox, the Mode is set to TwoWay.  This tells the control to push any changes back to the property.  Since the property has notification built in (since it is a Dependency Property), the second control will get updated automatically; it is bound to the same property.

As a rule of thumb, use Dependency Properties if your class derives from DependencyObject.  Use INotifyPropertyChanged in all other cases.

Binding to Other Elements

In addition to binding to data, you may also need to bind to values in the view.  The previous example shows some of this; the data contexts for the text boxes are the root elements instead of whatever was set earlier.

You can bind to another element by name:

<StackPanel Orientation="Horizontal">
    <TextBox Width="100" x:Name="input" />
    <TextBox Width="100" Text="{Binding ElementName=input, Path=Text}" />
</StackPanel>

In this example, the text of the second TextBox is bound to the text of the first TextBox.  Since this binding is not TwoWay, the value changes are not reciprocal.

Binding to Chained Properties

In all the examples thus far, data binding has happened on a property of the data context.  This may not be the case when the data’s object tree is more complex.  You can get the First and Last name properties, which are properties of a different object, from the data model using property chaining:

<TextBlock Text="{Binding Person.FullName.First'}" />

The same notification rules apply; the UI will update if First is a notifiable property.

Formatted Text

If you need to format the text display of a given value, you can do so using the StringFormat attribute in the binding declaration.  Building on the previous example, the text is displayed as “Your name is: Brian”:

<TextBlock Text="{Binding Person.FullName.First, StringFormat='Your name is: {0}'}" />

Value Converters

Often, the format of the data is more complex than a simple string format.  In cases like this, you can use Value Converters.  These are classes that implement IValueConverter and provide functions for Convert and ConvertBack.  Whenever binding occurs, the value is passed to the Value Converter which in turn translates the data to be displayed in the UI. 

Here is an example displaying a number with two digits of precision:

<UserControl.Resources>
    <local:NumberValueConverter x:Name="numeric" Precision="2" />
</UserControl.Resources>

<TextBox Width="100" x:Name="number" />
<TextBlock Text="{Binding ElementName=number, Path=Text, Converter={StaticResource numeric}}" />

The NumberValueConverter handles the conversion from a string value to a double and back to a string with the specified level of precision.  There are not many built-in Value Converters, but they are easy to build:

public class NumberValueConverter : IValueConverter
{
    public NumberValueConverter()
    {
        Precision = 4;
    }

    public int Precision { get; set; }

    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is string))
            return DependencyProperty.UnsetValue;

        if (string.IsNullOrWhiteSpace(value as string))
            value = "0";

        if ((value as string).EndsWith("."))
            value = value + "0";

        var format = string.Format("{{0:F{0}}}", Precision);

        return string.Format(format, double.Parse(value as string));
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

Summary

Data binding is very powerful in Silverlight.  The previous examples highlighted the most common case data binding scenarios.  Certainly there are more details to cover for more complex cases, but you should understand data binding capabilities pretty well by now. 

Next, let’s see how Flex implements the same features.

Data Binding in Flex

Data binding in Flex is expression-based (as opposed to Silveright, which is declarative).  For any given property in the visual tree, the developer can use a binding syntax to declaratively state how to bind.  Since Flex is expression-based, it does not require a data context like in Silverlight.  These bindings can be created imperatively in code, but they are typically defined in MXML unless there is a more dynamic reason to do it differently.

Basic Example

To begin with, let us assume that we have a data object defined some place:

<fx:Declarations>
    <local:DataObject id="dataObject" simpleText="default" />
</fx:Dexlarations>

Since we named the data object with the id of dataObject, we can use it in a binding expression anywhere within scope:

<s:Label text="{dataObject.simpleText}" />

When the MXML code is compiled, the binding expression is compiled as well.  It gets turned into ActionScript 3 code just like everything else in the MXML markup.  The compiler re-writes the class to set the text from the dataObject object as defined in the expression.

Change Notification

Displaying data is great and very often, this is all you need.  Often, though, you need to update the UI when the property changes.  It becomes the data object’s responsibility to notify the listener (the UI) of the change so it knows to modify the text.

Typically, this is done with Bindable Properties.  This is how you do it in the DataObject class:

[Bindable]
public class DataObject
{
    public var simpleText:String;
}

Notice the [Bindable] meta tag that has been added to the DataObject class.  This meta tag tells the Flex compiler to re-write the public properties in this class to be notifiable.  It does this by employing the standard eventing mechanism found in ActionScript 3. 

In reality, the generated code looks a lot like the Silverlight notifiable properties; the key difference is that the Bindable flag does it for you.  There is no specific notifiable interface for notifiable properties but the code-generated convention is to name the event as “propertyChanged” where “property” is the actual name of the property; in this example, it is “simpleTextChanged”.

Enough of the details.  By doing this, you can have code like this that will update the text based on data binding when you press the button:

<s:Label text="{dataObject.simpleText}" />
<s:Button label="update" click="dataObject.simpleText = 'Updated'" />

The Flex compiler parses the binding expression and listens to change events on the dataObject instance.  When it changes, the Label.text property is set.  All of this is generated for you.

Binding to Local Variables

It is easy to bind to local variables since reading a local variable is noting but an expression in Flex.  For instance, you can define the variable as [Bindable] in the script block:

[Bindable]
private var localText:String = "";

Then you simply bind to the variable:

<s:TextInput text="@{localText}" />
<s:TextInput text="{localText}" />

Notice that the first text box use the “@” symbol.  This tells the binding system that the binding is two-way.  In other words, anything typed into the first TextInput will get set in the localText variable and then sent back to the second TextInput.

Using Expressions

The power of using expressions for data binding becomes obvious when you call methods within the binding.  In this example, we can add two values using data binding alone.  When a or b change, the binding expression is automatically re-evaluated, causing the output to change:

<s:TextInput id="a" />
<s:TextInput id="b" />
<s:Label text="a + b = {add(Number(a.text), Number(b.text))}" />

Although I don’t recommend putting too much logic in the binding expressions, the power provided here is quite amazing.  One way I find myself using this feature while implementing the Presentation Model pattern is by hiding elements based on if data exists.  A simple example of binding the visible property to the existence of the nullableObject variable:

<s:Label text="Value is not null" visible="{nullableObject != null}" />
<s:Button label="Make null" click="nullableObject = null" />
<s:Button label="Set value" click="nullableObject = 'something'" />

Binding to Other Elements

In addition to binding to data, you may also need to bind to values in the view.  You can bind to another element by id since setting an id on a visual element automatically references it in a variable of the same name:

<s:TextInput id="input" />
<s:TextInput text="{input.text}" />

In this example, the text of the second TextInput is bound to the text of the first TextInput.  Since this binding is not TwoWay, the value changes are not reciprocal.

Binding to Chained Properties

In all the examples thus far, data binding has happened on a property of a single object.  This may not be the case when the data’s object tree is more complex.  You can get the First and Last name properties out of the data model by using property chaining:

<fx:Declarations>
    <fx:Model id="model">
        <person>
            <name>
                <first>Brian</first>
                <last>Genisio</last>
            </name>
        </person>
    </fx:Model>
</fx:Declarations>

<s:Label text="{model.name.first}" />

The same notification rules apply; meaning that the UI will update if First is a notifiable property.  In the case of fx:Model, all properties are inherently bindable.

In order for change notification to occur on the chained properties to update on change, all of the properties in the chain must be [Bindable].

Formatted Text

Since data binding is based on an evaluated expression, adding text before or after the bound value is very easy:

<s:Label text="Your name is: {model.name.first}" />

In this example, the UI will display “Your name is: Brian”.

Formatters

Since data binding is based on expressions, data can be formatted using functions in the expression that get evaluated every time a bindable property changes.  In addition, Flex provides several formatters out of the box.  The following example shows how to set the precision of a double value to 2 digits after the decimal place:

<fx:Declarations>
    <mx:NumberFormatter id="numeric" precision="2" />
</fx:Declarations>

<s:TextInput id="number" />
<s:Label text="{numeric.format(Number(number.text))}" />

Whenever the number.text property changes, it uses the NumberFormatter to evaluate the text in the Label.  In addition to the numerous built-in formatters (currency, date, phone number, etc), you can create your own formatters by extending Formatter

Summary

The capabilities provided by data binding in Silverlight and Flex give the developer an extremely powerful tool.  It allows him/her to write more features with less code.  Silverlight uses a declarative model where Flex uses an expression model, but the majority of the capabilities mirror each other.  Data binding is a case where I think Flex has the upper hand, though.  By using expressions, the data binding is both more succinct and more powerful.  That is not to say that the declarative style in Silverlight is bad.  It is just that the expressive side in Flex is better (in my opinion). 

I am VERY curious to see how C# 5 with the compiler as a service adds value to the binding story in Silverlight.  Will we see an optional expression-based binding that is compiled and evaluated at runtime?  If not, how hard will it be to write this?

Next time, I will write about visualizing data in Silverlight and Flex. Stay tuned Smile

Tags: , , ,

6 Responses to “Cross-Training in Silverlight & Flex–Data Binding”

  1. Cross-Training in Silverlight & Flex – Data Binding…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. [...] This post was mentioned on Twitter by Brian Genisio, Mariano Ravinale. Mariano Ravinale said: RT @BrianGenisio: Blogged: Cross-Training in Silverlight & Flex — Data Binding http://j.mp/hx1geb #flex #silverlight [...]

  3. [...] Brian Genisio’s House of Bilz One of the most powerful and compelling features of RIA frameworks like Silverlight and Flex is [...]

  1. Manas says:

    Awesome thanks for providing such a good article .I am completely unknown to Flex but your article gives us a clear picture.
    Thanks again.

  2. Somesh Batra says:

    Informative post!! It helped me lot. There are some good articles too I was found over internet which also explained very about complex data binding in silver light. Url of those posts are….
    http://msdn.microsoft.com/en-us/library/cc278072%28v=vs.95%29.aspx

    http://www.codeproject.com/Articles/80555/Databinding-in-Silverlight-applications

    http://mindstick.com/Articles/d9362d1c-8c5d-42ed-8677-4ecf08eed57b/?Complex%20Data%20Binding%20in%20Silverlight

Leave a Reply