More on XML Data Binding

In my last post I demonstrated how to bind elements from an XML document to WPF controls. I created small master/detail dual pane application to demonstrate this. Here I continue exploring XML data binding using the same XML document but with these important differences.

  1. The XML document will use namespaces.
  2. The data will be sorted in a different order.
  3. The view of the data will be flattened into a ListView.

Using XML Namespaces

Adding a namespace to the XML document itself is a simple matter. Once this is done, however, changes must be made to the code that accesses the now namespace scoped XML elements and attributes. First, here’s the updates XML document.

<pc:States xmlns:pc="https://patconroy.wordpress.com/States/">
    <pc:State pc:Name="Delaware" pc:Abbrev="DE">
        <pc:Capital>Dover</pc:Capital>
        <pc:Nickname>The First State</pc:Nickname>
        <pc:Bird>Blue Hen Chicken</pc:Bird>
        <pc:Flower>Peach Blossom</pc:Flower>
        <pc:Tree>American Holly</pc:Tree>
        <pc:Motto>Liberty and Independence</pc:Motto>
    </pc:State>
    <!-- Other states omitted for brevity -->
</pc:States>

The application no longer displays the data after making this change. It turns out that two changes must be made to the XAML source. First an XmlNamespaceMappingCollection must be associated with the XmlDataProvider. The XmlNamespaceMappingCollection creates a mapping between namespace URIs and their prefixes that are later used in XPath expressions. The XmlDataProvider.XmlNamespaceManager property must be set to an instance of XmlNamespaceMappingCollection. Here I create a mapping between the prefix “pc” and my namespace URI http://patconroy.workpress.com/States/.

<XmlNamespaceMappingCollection x:Key="StateDataNamespaceMapping">
    <XmlNamespaceMapping Uri="https://patconroy.wordpress.com/States/" Prefix="pc" />
</XmlNamespaceMappingCollection>
<XmlDataProvider x:Key="StateData" XmlNamespaceManager="{StaticResource StateDataNamespaceMapping}">
    <!-- etc. -->
</XmlDataProvider>

Next the XPath expressions used in the application must be updated to use the “pc” prefix. Without the prefix the XPath processor looks for elements and attributes in the global namespace, and this in no longer the case. The state XPath expression to access the state collection now becomes //pc:States/pc:State instead of //States/State. The expression to access the Name attribute of the State element now becomes @pc:Name.

Sorting the Data

In the XML document the states are presented in the order in which they ratified the Constitution for the United States of America. Any ItemsControl, including the ListBox used in the last example and the ListView used here, will display them in this order when bound to the XmlElement collection returned by the XPath expression //pc:States/pc:State. In this application I want them alphabetized by state abbreviation. WPF includes the CollectionViewSource class to do exactly this. CollectionViewSource can also do grouping and filtering. Check MSDN for the details. Here I create a CollectionViewSource in the main window’s resource dictionary to sort on the Abbrev XML attribute.

<CollectionViewSource x:Key="StateViewSource" Source="{Binding Source={StaticResource StateData},XPath=//pc:States/pc:State}">
    <CollectionViewSource.SortDescriptions>
        <cm:SortDescription PropertyName="@pc:Abbrev"/>
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

The CollectionViewSource binds to the XmlDataProvider and applies an XPath expression to access the collection of State elements. A SortDescription is added to sort on the Abbrev attribute, which is again accessed using an XPath expression. The SortDescription class doesn’t exist in any of the default XAML namespaces, so the namespace declaration xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase" must be added to the XAML. The ItemsControl displaying this data must bind to the CollectionViewSource, not the XmlDataProvider: ItemsSource="{Binding Source={StaticResource StateViewSource}}".

Displaying in a ListView

In previous posts I re-templated the ListView control. As part of this I implemented alternating row colors to achieve an accounting ledger look. The accounting ledger look can be achieved far more simply than this; it isn’t necessary to re-template the entire control. When working with .Net 3.5 SP1 apply the AlternationCount attribute to the ListView itself. Then add an ItemContainerStyle containing the property triggers on ItemsControl.AlternationIndex as shown in the previous post. I had to create a DataTemplate for the first column in order to display the state flag there. A value converter is used to obtain the image file path. Thanks again to folks at 3DFlags.com for the flag images. Here’s the complete ListView XAML for this project.

<ListView x:Name="_stateList" Margin="4"
          AlternationCount="2"
          ItemsSource="{Binding Source={StaticResource StateViewSource}}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="Khaki"/>
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="Beige"/>
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="LightBlue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView AllowsColumnReorder="true">
            <GridViewColumn Width="36">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding XPath=@pc:Abbrev, Converter={StaticResource ImageNameConverter}}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Width="48" DisplayMemberBinding="{Binding Path=@pc:Abbrev}" Header="Abbrev"/>
            <GridViewColumn Width="100" DisplayMemberBinding="{Binding Path=@pc:Name}" Header="Name"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Nickname}" Header="Nickname"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Capital}" Header="Capltal City"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Bird}" Header="State Bird"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Flower}" Header="State Flower"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Tree}" Header="State Tree"/>
            <GridViewColumn Width="200" DisplayMemberBinding="{Binding XPath=pc:Motto}" Header="Motto"/>
        </GridView>
    </ListView.View>
</ListView>

Here’s how the finished application looks.
xmllistview

Source code can be downloaded here.

Advertisements

0 Responses to “More on XML Data Binding”



  1. Leave a Comment

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




January 2009
M T W T F S S
« Dec   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  
I am a part of all that I have met;
Yet all exprience is an arch whitherthro'
Gleams that untravell'd world, whose margin fades
For ever and for ever when I move.
How dull it is to pause, to make an end,
To rust unburnish'd, not to shine in use!
Alfred, Lord Tennyson

%d bloggers like this: