RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Flexible and Powerful Data Binding with WPF, Part 2

Microsoft has been building data binding frameworks for years. Each one promises to solve our data binding woes forever. We're still waiting for the perfect one—but we're getting closer!

ll applications are dependent on data in some form and most developers find themselves writing reams of data access code. The first article in this series discussed how to control the data binding mechanisms of WPF programmatically. Along with a programmatic interface, WPF also provides a declarative data binding interface, which is the topic of this article.

XAML Binding

It's possible to set up a binding using only XAML. The XAML parser understands how to parse and instantiate many of the WPF framework classes, but doesn't know how to work with non-WPF classes unless they're registered with the parser. Therefore, the first step in using a custom data source is to associate an XML namespace with a CLR namespace. The following XAML snippet shows how to set up an xmlns "sys" namespace for the System namespace in mscorlib and a "local" namespace for a custom assembly:

  xmlns:local='clr-namespace:MyLib' />
Next, you need to create an instance of the type and store it in a discoverable location. In C#/Visual Basic, you would create a variable and instantiate the type. In XAML, you have to put the instance in a resources section. The XAML parser instantiates your tTeype and adds the instance to the resource dictionary. You provide a key for the resource so that you can retrieve the instance later:

  <!-- Instantiate a string
       and load into resource dictionary -->
  <sys:String x:Key='sample'>ABC 123 DEF 456
  <!-- Instantiate an employee
       and load into resource dictionary -->
  <local:Employee x:Key='emp'
Now you can set up the binding in the main part of the page and employ the Source property for the configuration. Set the Source property to refer to an instance of an object, in this case the sample string declared in the Page.Resources section shown previously. Bind the first TextBlock directly to the string and use a Path for the second TextBlock to show the second Char in the String.Chars array:

     Text="{Binding Source=
     {StaticResource sample}}" />
   <TextBlock Text="{Binding Source=
    {StaticResource sample},Path=[2]}" />
The next example shows comparable XAML that binds to the Employee object:

     Text="{Binding Source=
     {StaticResource emp},Path=LastName}" />

Relative Source Binding

It's not necessary (or desirable) to name every element in a WPF logical tree, which can pose a problem when binding to other elements. Use the ElementName property to specify a named element as the source. There are times when you won't know the element name but you'll want to bind to it anyway.

WPF is a complete rethinking of how to construct a UI development platform. Because Microsoft started with a blank slate, the WPF architects took the opportunity to engineer interesting ideas into their binding engine.
Sometimes you just want to say; "Bind to my parent StackPanel" or "Bind to the previous item in this list." Another example is when you want to bind to a different property of the same element. In other words, you need a way to configure the element binding without requiring an element name—and XAML provides one. Use the RelativeSource property when you need an element binding, but can't use the ElementName property.

There are four modes available for RelativeSource bindings, but only two are relevant to this article:

  • Self: Reference any property on the current object. The next example shows some XAML that binds the TextBox Background property to the Text property on the same TextBox. Note that the example nests one markup extension within another. Run the application and try typing "Red" or "#FF336688" in the text box to see the background color change:
   <TextBox  Text='#FF55FFCC'      
     Background='{Binding Text,
     RelativeSource={RelativeSource Self }}'/>
  • FindAncestor: This binding walks the tree of parent elements looking for a specific type of ancestor element. You must specify the AncestorType (a DockPanel in the following example), to create the binding successfully. Use the AncestorLevel to skip over parent levels. For example, setting AncestorLevel=2 will skip one generation. This example binds the TextBox Background attribute to its grandparent DockPanel (so it will be blue):

   <DockPanel Background='Blue'>
     <DockPanel Background='Green'>
       <TextBox Margin='20'
         Background='{Binding Background ,
         RelativeSource={RelativeSource FindAncestor,
         AncestorType=DockPanel ,
         AncestorLevel=2}}' />
Author's Note: The two RelativeSource modes not relevant to this article are TemplatedParent and PreviousData.

Editor's Note: This article was first published in the January/February 2009 issue of CoDe Magazine, and is reprinted here by permission.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date