Click here to Skip to main content
15,880,967 members
Articles / Desktop Programming / WPF

How to Perform WPF Data Binding Using LINQ to XML

Rate me:
Please Sign up or sign in to vote.
4.00/5 (8 votes)
3 Jul 2009CPOL7 min read 56.7K   9   14   5
This article explains how to perform data binding to WPF controls using LINQ to XML.

System.Xml.Linq

Before binding XML data with WPF controls, let me give you an overview of the System.Xml.Linq namespace. It contains the classes for LINQ to XML. LINQ to XML is an in-memory XML programming interface that enables you to modify XML documents efficiently and easily.

Using LINQ to XML, you can:

  1. Load XML from files or streams.
  2. Serialize XML to files or streams.
  3. Create XML trees from scratch using functional construction.
  4. Query XML trees using LINQ queries.
  5. Manipulate in-memory XML trees.
  6. Validate XML trees using XSD.
  7. Use a combination of these features to transform XML trees from one shape to another.

For data binding efforts, we need to focus on two classes in this namespace, namely: XAttribute and XElement. The dynamic properties of these classes help us to exactly bind the control to the respective elements in the XML data.

The XAttribute class is derived from the XObject class and it represents an XML attribute. Attributes are not derived from XNode; they are not nodes in the XML tree. Instead, they are simply name/value pairs associated with an element.

The XElement class is derived from the XContainer class which derives from the XNode class, and it represents an XML element, the fundamental XML construct. An element has an XName, optionally one or more attributes, and can optionally contain contents like XElement, XComment, XText, and XProcessingInstruction.

Each XElement contains a list of attributes for that element. Attributes must have a qualified name that is unique to the element.

As an example, the following C# code shows the common task of creating an element that contains an attribute:

C#
XElement phone = new XElement("Phone", 
  new XAttribute("Type", "Home"), "555-555-5555");
Console.WriteLine(phone);

Dynamic Data Binding in WPF and Dynamic Properties

Having learnt that we have a couple of XLinq classes available with us, the next step is to understand how data binding can be performed with these classes.

By default, data binding occurs only when the target UI element is initialized. This is called one-time binding. For most purposes, this is insufficient; with two-way binding, changes to the source are automatically propagated to the target, and changes to the target are automatically propagated to the source.

For one-way or two-way binding to occur, the source must implement a change notification mechanism, for example, by implementing the INotifyPropertyChanged interface or by using a PropertyNameChanged pattern for each property supported.

Most LINQ to XML classes do not qualify as proper WPF dynamic data sources. To support WPF data binding, LINQ to XML exposes a set of dynamic properties. These dynamic properties are special run-time properties in the XAttribute and XElement classes to act as dynamic data sources for WPF and implement change notifications.

The dynamic properties in the XAttribute and XElement classes cannot be accessed like standard properties. In C#, dynamic properties can only be accessed at run time through facilities provided by the System.ComponentModel namespace. However, in an XML source, dynamic properties can be accessed through a straightforward notation in the following form: object.dynamic-property.

The dynamic properties for these two classes either resolve to a value that can be used directly, or to an indexer such as Elements and Descendants property of XElement, that must be supplied with an index to obtain the resulting value or collection of values.

To implement WPF dynamic binding, dynamic properties will be used with facilities provided by the System.Windows.Data namespace, most notably the Binding class.

XML as Resource Data in XAML

Now, let us look at the various elements of XAML that can be used to define and use XML data. Also, this section explains the elements required for defining the resources, templates, and subsequent binding of these to the WPF controls.

Inside the Windows.Resources tag, we can declare the data source to XML data using the <ObjectDataProvider> and also a <DataTemplate> that follows a certain pattern of data elements.

The <ObjectDataProvider> tag declares an instance of ObjectDataProvider class, named LoadedBooks that uses an XElement as the source. This XElement is initialized by parsing an embedded XML document (a CDATA element). Also, white space is preserved when declaring the embedded XML document and when it is parsed. The reason is that the TextBlock control, which is used to display the raw XML, has no special XML formatting capabilities.

A DataTemplate named “BookTemplate” is defined to display the entries in the respective controls in the Book List UI section. It uses data binding and LINQ to XML dynamic properties to retrieve the book ID and book name through the following assignments:

XML
Text="{Binding Path=Attribute[id].Value}"
Text="{Binding Path=Value}"

<--<Window.Resources> tag with both 
  of these definitions is given below:-->
<Window.Resources>
    <!-- Books provider and inline XML data -->
    <ObjectDataProvider x:Key="LoadedBooks" 
      ObjectType="{x:Type xlinq:XElement}"
      MethodName="Parse">
        <ObjectDataProvider.MethodParameters>
            <system:String xml:space="preserve">
<![CDATA[
<books xmlns="http://www.mybooks.com">
<book id="1">Seven ways to Success</book>
<book id="2">My Experiments with Truth</book>
<book id="3">Leadership Skills</book>
<book id="4">India and Politics Today</book>
</books>
]]>                
            </system:String>
            <xlinq:LoadOptions>PreserveWhitespace</xlinq:LoadOptions>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

    <!-- Template for use in Books List listbox. -->
    <DataTemplate x:Key="BookTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Margin="3" Text="{Binding Path=Attribute[id].Value}"/>
            <TextBlock Margin="3" Text="-"/>
            <TextBlock Margin="3" Text="{Binding Path=Value}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

Once the DataTemplate is ready as a data resource, data binding can be performed with the WPF controls in the user interface.

In the <StackPanel> tag, the DataContext property is set to the “LoadedBooks” data provider.

DataContext="{Binding Source={StaticResource LoadedBooks}}

This makes it possible for the TextBlock named tbRawXml to display the raw XML by binding to this data provider's Xml property:

Text="{Binding Path=Xml}"

The ListBox in the Book List UI section sets the template for its display items to the BookTemplate resource, and the actual values of the books are bound to the items in the list box.

XML
<ListBox Name="lbBooks" Height="200" 
  Width="415" ItemTemplate ="{StaticResource BookTemplate}">
    <ListBox.ItemsSource>
        <Binding Path="Elements[{http://www.mybooks.com}book]"/>
    </ListBox.ItemsSource>
</ListBox>

Upon selecting a book in the list box, we need to display the corresponding details in the textboxes for viewing and editing purposes. This requires a binding to the parent data source in the listbox, and a two way data binding so that the current values of the book elements are displayed to and updated from the two text boxes in this panel. Data binding to dynamic properties is similar to that used in the BookTemplate data template:

XML
   <StackPanel Margin="1" 
     DataContext="{Binding ElementName=lbBooks, Path=SelectedItem}">
....
....
        <TextBox Name="editAttributeTextBox" 
          Width="410" Text="{Binding Path=Attribute[id].Value}">
...
...
          <TextBox Name="editValueTextBox" Width="410" 
            Text="{Binding Path=Value}" Height="25">

Walkthrough: Creating a WPF application that shows LINQ to XML Data Binding with Inline XML Data

Now, let us create a complete application that would make use of the above discussed features. This sample program enables the user to view and manipulate a list of books that is stored as an embedded XML element.

Start Visual Studio and create a C# WPF application named WPFDataBindingLinqToXml. The project must use the .NET Framework 3.5 (or later).

Design the UI as shown in the screenshot below as XAML markup in the Window1.Xaml.

wpfdatabindinglinqtoxml-part1.jpg

Also, modify the code in the Window1.Xaml.cs file as below:

C#
XNamespace mybooks = "http://www.mybooks.com";
XElement bookList;

public Window1()
{
    InitializeComponent();
    bookList = (XElement)((ObjectDataProvider)Resources["LoadedBooks"]).Data;
}
void OnRemoveBook(object sender, EventArgs e)
{
    int index = lbBooks.SelectedIndex;
    if (index < 0) return;

    XElement selBook = (XElement)lbBooks.SelectedItem;
    //Get next node before removing element.
    XNode nextNode = selBook.NextNode;
    selBook.Remove();

    //Remove any matching newline node.
    if (nextNode != null && nextNode.ToString().Trim().Equals(""))
    { nextNode.Remove(); }

    //Set selected item. 
    if (lbBooks.Items.Count > 0)
    { lbBooks.SelectedItem = lbBooks.Items[index > 0 ? index - 1 : 0]; }
}

void OnAddBook(object sender, EventArgs e)
{
    if (String.IsNullOrEmpty(tbAddID.Text) || 
        String.IsNullOrEmpty(tbAddValue.Text))
    {
        MessageBox.Show("Please supply both a Book ID and a Value!", "Entry Error!");
        return;
    }
    XElement newBook = new XElement(mybooks + "book", 
             new XAttribute("id", tbAddID.Text),
                        tbAddValue.Text);
    bookList.Add("  ", newBook, "\r\n");
}

Basically, the above code uses the XElement, XNode, and XNamespace objects to manipulate XML data along with binding controls.

Lastly, build the solution by pressing Ctrl+Shift+B, and then run it by pressing F5. The project should compile without errors and run as a generic WPF application.

Using the WPFDataBindingLinqToXml sample application and its User Interface

The top section of the UI displays the raw XML that represents the book list. It is displayed using a WPF TextBlock control, which does not enable interaction through the mouse or keyboard.

The second vertical section, labeled Book List, displays the books as a plain text ordered list. It uses a ListBox control that enables selection though the mouse or keyboard.

The following tasks may be performed in this UI:

  • To delete an existing book from the list, select it in the Book List section, then click the Remove Selected Book button. Notice that the book entry has been removed from both the book and the raw XML source listings.
  • To add a new book to the list, enter values into the ID and ValueTextBox controls in the last section, Add New Book, and then click the Add Book button. Note that the book is appended to the list in both the book and XML listings. This program does not validate input values.
  • Select the book entry in the second Book List section. Its current values should be displayed in the third section.
  • To Edit Selected Book, edit the values using the keyboard. As soon as either TextBox control loses focus, changes are automatically propagated to the XML source and book listings.

Conclusion

This article has explained the theory and steps involved in developing a WPF application that can bind to XML data stored inline using LINQ to XML classes. The same can also be done with XML data stored in a file system. The next part of this article would explain how to bind to an external XML data with slighter modifications in this sample. Hope you enjoyed and found this article useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder BB Systems CIT-GPNP
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow {Binding Path=Xml} worked? Pin
anujwadhva21-Apr-16 14:50
anujwadhva21-Apr-16 14:50 
General[My vote of 1] Missing Code, Near-Duplicate of MSDN resources Pin
Benjamin Holland22-Nov-15 13:38
Benjamin Holland22-Nov-15 13:38 
GeneralSetting ObjectDataProvider source in backend code Pin
thegeoff22-Feb-11 21:13
thegeoff22-Feb-11 21:13 
GeneralMy vote of 1 Pin
Neverrav1-Aug-10 22:21
Neverrav1-Aug-10 22:21 
GeneralMy vote of 2 Pin
Allan Kiss6-May-10 21:49
Allan Kiss6-May-10 21:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.