Tuesday 10 July 2012

Simple Binding in WPF

For the last few weeks I have been learning WPF and I decided to introduce the concept of binding in WPF.

What is it?

In its most simple form, binding is a technique used to synchronize one property with another either on the same element or on two completely different elements. The Binding class is what is known as a Markup Extension class, in XAML these are defined by the use of curly braces when set as an attribute of an element - it allows the use of positional and named parameters as with .NET attribute definitions, or by using property element syntax (defining an XAML attribute as an XAML child element). Let's take a look at an example of binding the content on a label to the text on a textbox:

<StackPanel Width="200" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <TextBox Name="txt"/>
  <Label Content="{Binding ElementName=txt, Path=Text}" />
</StackPanel>
Binding to a TextBox's Text in WPF
The binding class has a default constructor, but it also has a constructor that accepts a single parameter - the string for the property path, so here is a better way of writing the binding string above, using Path as the positional parameter, and ElementName as the named parameter:

<Label Content="{Binding Text, ElementName=txt}" />
You can use the Path property the same way you access properties in code (eg. List.Count), the folloowing example shows this in action as well as binding to a property on the same element:
<StackPanel Width="200" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">   
  <ComboBox Background="{Binding SelectedItem.Background, RelativeSource={RelativeSource Self}}">
    <ComboBoxItem Background="Red">Red</ComboBoxItem>
 <ComboBoxItem Background="Green">Green</ComboBoxItem>
 <ComboBoxItem Background="Blue">Blue</ComboBoxItem>
  </ComboBox>
</StackPanel>
Binding a ComboBox background to the Background of its SelectedItem
Notice that the value of the RelativeSource property is in curly braces, this is because RelativeSource is also a Markup Extension class, where the positional parameter Mode is set to Self.

When an item is selected, the background of the selected item will be set to the background of the ComboBox itself, but no item is originally selected so the background will be originally set to null (completely transparent). To fix this I will use the FallbackValue property when binding, this allows us to specify a value will be set if binding to the specified path fails (in this case it fails because SelectedItem is initially null). Because there is no simple string value that converts into a complex LinearGradientBrush (the default background of a ComboBox and other Windows controls), the binding on the background can be created by using property elements, this means properties can have more complex values, here is how it is done:

<StackPanel Width="200" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <ComboBox>
    <ComboBox.Background>
      <Binding>
        <Binding.Path>SelectedItem.Background</Binding.Path>
        <Binding.RelativeSource>
          <RelativeSource Mode="Self"/>
        </Binding.RelativeSource>
        <Binding.FallbackValue>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="#FFF" Offset="0.0"/>
                <GradientStop Color="#CCC" Offset="1.0"/>
              </GradientStopCollection>
            </GradientBrush.GradientStops>
          </LinearGradientBrush>
        </Binding.FallbackValue>
      </Binding>
    </ComboBox.Background>

    <ComboBoxItem Background="Red">Red</ComboBoxItem>
    <ComboBoxItem Background="Green">Green</ComboBoxItem>
    <ComboBoxItem Background="Blue">Blue</ComboBoxItem>
  </ComboBox>
</StackPanel>
Now the ComboBox will have its default background colour again until an item is selected.

No comments: