IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

WPF XML Data Binding and Selection Synchronization

Saturday 31 March, 2007, 07:31 PM

There's a problem people often run into when using XML data binding in WPF. If you bind a ListBox to a collection of items, the IsSynchronizedWithCurrentItem property sometimes doesn't appear to work as you'd expect. Here's an example of the problem:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Page.Resources>
    <XmlDataProvider x:Key="src">
      <x:XData>
        <data xmlns=''>
          <item name="One" />
          <item name="Two" />
          <item name="Three" />
        </data>
      </x:XData>
    </XmlDataProvider>
  </Page.Resources>

  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <ListBox IsSynchronizedWithCurrentItem="True"
        ItemsSource="{Binding Source={StaticResource src}, XPath=/data/item}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

    <TextBlock Grid.Column="1"
       Text="{Binding Source={StaticResource src}, XPath=/data/item/@name}" />

  </Grid>
</Page>

This example contains a simple embedded XML data source. It binds a ListBox to the <item> elements in that source, with a DataTemplate showing the item's name attribute. There's also a TextBlock that sits next to the ListBox, bound to the same information. Since the list box's IsSynchronizedWithCurrentItem property is set to True, you might reasonably expect the text block to reflect the current selection in the list box. But as you can see, it doesn't:

A list unsynchronized with an item

The text block on the right has got stuck on the first item, even though the list box is on the second. What's happening? There are two things you need to understand which, between them, explain what's going on here:

Bearing this in mind, look at the two Binding expressions in the example above. They both independently evaluate to a sequence of nodes. And they're not even the same nodes. The list box's ItemsSource is bound with an XPath expression that evaluates to a sequence of XmlElement objects, representing the <item> elements in the source. The TextBlock is bound with an XPath expression that evaluates to a sequence of XmlAttribute objects, representing the name attributes of the <item> elements in the source.

So that's two distinct collection objects that contain two completely different sets of objects. We shouldn't really be surprised that WPF treats the two as being unrelated. Unfortunately, that's not really what we wanted here, but we can fix this fairly easily.

Bind to the List Just Once

If you want to keep bound elements synchronized with the current selection, there's one simple rule to remember when using XML data binding: make sure you've only got one binding expression that generates the collection.

The problem with the earlier example is that it has two bindings that both generate their own version of the collection. Here's a modified version that only generates the collection once:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Page.Resources>
    <XmlDataProvider x:Key="src">
      <x:XData>
        <data xmlns=''>
          <item name="One" />
          <item name="Two" />
          <item name="Three" />
        </data>
      </x:XData>
    </XmlDataProvider>
  </Page.Resources>

  <Grid DataContext="{Binding Source={StaticResource src}, XPath=/data/item}">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <ListBox IsSynchronizedWithCurrentItem="True"
        ItemsSource="{Binding}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

    <TextBlock Grid.Column="1"
       Text="{Binding XPath=@name}" />

  </Grid>
</Page>

We've now got an extra binding. In the Grid that contains the rest of the UI we've bound the DataContext to the collection of <item> elements. Critically, this is now the only binding that generates a collection. The ListBox now just binds directly to the DataContext. Its binding doesn't even contain an XPath expression, so it won't attempt to generate a collection of its own. And while the text block still contains an XPath expression, it's not an absolute path. It's a relative path that will be evaluated relative to the data context. And its data context is the exact same collection that the list box is bound to.

In short, the list box and text block now share the same underlying collection object. Consequently, they now remain in sync: the text block shows the name attribute for the currently selected item in the list box.

Object Binding

You won't see this problem when binding to objects. It is essentially a problem specific to XML data binding. This is because with XML data binding, collections are generated on the fly. XML documents don't have an intrinsic notion of a collection, so we rely on XPath expressions to build collections when we need to present lists. But an object model typically provides collections or arrays to represent sequences of items, so there's no need for the data binding layer to generate such things.

Since with object models, data binding will never generate a collection for you, you tend not to run into the problem discussed in this blog. But XML binding has to generate collections based on the XPath expressions you give it. And that's why you need to be careful about where you bind to a collection when using XML data sources.

Copyright © 2002-2013, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk