Pages

Sunday, July 18, 2010

XML Binding in WPF with Sample RSS reader

XAML being getting more and more popular is also introduced for Mobile applications. Recently while I was exploring on the internet, I found that the recent version of Windows 7 mobile interfaces uses Silverlight to deal with the interface. Just after the initial thought, I thought to try it for just to increase my knowledge base. Hence, I installed it to my machine and tried. It works great and I am really excited to see that Silverlight is again introduced with this mobile.

Inspite of having XNA for truely 3D style of application building, I tried simple programs to use this edition of silverlight and it worked greatly. It works in the most simplest way as with normal silverlight applications.

While doing the simple application, I found the XML binding within WPF application as an interesting part of XAML bindings. In this post, I will discuss how you can implement binding of a property with an XMLDataSource.

XML is very important part for any application. While you create your application, we generally need to write lot of code to handle XML data stream. May be from your local machine, or using WebClient to download data from your web server. WPF has in built support for XML bindings. Lets discuss XML bindings in detail using sample code.

Say you have an XML like this :

<data>
  <packet id="names">
    <Names description="All are selected">
      <nametype id="1" firstname="raja" lastname="das">58</nametype>
      <nametype id="2" firstname="anjan" lastname="chowdhuri">67</nametype>
      <nametype id="3" firstname="charu" lastname="singh">38</nametype>
      <nametype id="4" firstname="manju" lastname="sen">69</nametype>
      <nametype id="5" firstname="sanju" lastname="sharma">89</nametype>
      <nametype id="6" firstname="sanjana" lastname="mathur">77</nametype>
    </Names>
  </packet>
</data>

Now let us create a code that binds each elements of the above xml.

<Window.Resources>
        <XmlDataProvider Source="myxmldata.xml" x:Key="xdata" XPath="/data/packet/Names"></XmlDataProvider>
    </Window.Resources>

So first of all we have added a new window, and added the XmlDataSource as resource. Please note that we can also use x:Data to define the XmlDataSource Xml directly within the file itself like :

<XmlDataProvider x:Key="xdata" XPath="/data/packet/Names">
            <x:XData>
                <data xmlns="">
                    <packet id="names">
                        <Names description="All are selected">
                            <nametype id="1" firstname="raja" lastname="das">58</nametype>
                            <nametype id="2" firstname="anjan" lastname="chowdhuri">67</nametype>
                            <nametype id="3" firstname="charu" lastname="singh">38</nametype>
                            <nametype id="4" firstname="manju" lastname="sen">69</nametype>
                            <nametype id="5" firstname="sanju" lastname="sharma">89</nametype>
                            <nametype id="6" firstname="sanjana" lastname="mathur">77</nametype>
                        </Names>
                    </packet>
                </data>
            </x:XData>
        </XmlDataProvider>

Please note that I have added the xmlns in data tag intentionally, as if you dont the xml will inherit from the base Namespace.
The XPath within the XmlDataProvider induces the read of XML from that path. So for our XML the data will be read after /data/packet/names.

So lets begin with bindings.
<Grid DataContext="{StaticResource xdata}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding XPath=@description, StringFormat='{}Status: {0}'}" Grid.Row="0"/>
        <ListBox x:Name="lstNames" ItemsSource="{Binding XPath=nametype}" IsSynchronizedWithCurrentItem="True" Grid.Row="1" SelectionChanged="lstNames_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock>
                        <TextBlock.Text>
                            <MultiBinding StringFormat="{}{0} {1} Got {2}">
                                <Binding XPath="@firstname"></Binding>
                                <Binding XPath="@lastname"></Binding>
                                <Binding XPath="text()"></Binding>
                            </MultiBinding>
                        </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StatusBar Grid.Row="2">
            <TextBlock Text="Roll Number :"></TextBlock>
            <TextBlock x:Name="txtRoll"></TextBlock>
            <Separator/>
            <TextBlock Text="You Got : "></TextBlock> 
            <TextBlock Text="{Binding ElementName=lstNames, Path=SelectedItem.InnerText}"/> 
        </StatusBar>
    </Grid>

In the above XAML code, you can see I have put the datacontext of the Grid to the XmlDataProvider resource.

Keep in mind @ is used for attributes and / is used for tags. So the first TextBlock shows @description which means the string written within the description attribute of Names tag.

Now as we are in a collection of names, lets take a listbox to show all the elements within the XML data. The ItemsSource allows you to bind data with specific XPath. Here we have used nametype, as our main collection is of nametype. Within the datatemplate, we place one TextBlock for which the data is multi-bound. We use firstname and lastname attribute to put binding on the TextBlock Text property. In this situation, you can see, I have used @firstname and @lastname which will ensure that the binder will evaluate the Attribute rather than the innerText. The StatusBar allow you to show the bound data for the SelectedItem of the ListBox.

Things to Remember :
  1. Use XPath to move to a particular node path.
  2. Move to currentElement using XPath and choose @ for attribute and text() to get the InnerText.
  3. / is used to move to the child nodes. 
  4. In case you define your xml within XAML, be sure to specify the namespace to blank. Otherwise it will inherit from XAML namespace.

A little RSS Reader

So as things are now clear, lets build a sample RSS reader.



RSS is a special XML schema, so when we load RSS into our XMLDataProvider, we need to parse it in a special format. So lets see how the XAML looks like.

<Window.Resources>
        <XmlDataProvider x:Key="dnt" 
                     Source="http://www.abhisheksur.com/feeds/posts/default?alt=rss" 
                     XPath="/rss/channel" />
    </Window.Resources>
    <StackPanel DataContext="{Binding Source={StaticResource dnt}}">
        <StackPanel>
            <TextBlock Text="Title : " />
            <Label Content="{Binding XPath=title}"/>
            <TextBlock Text="Description : "/>
            <Label Content="{Binding XPath=description}"/>
        </StackPanel>
        <ListBox    IsSynchronizedWithCurrentItem="True" 
                    ItemsSource="{Binding XPath=item}"
                    MaxHeight="500" 
                    ScrollViewer.CanContentScroll="False">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding XPath=title}" FontSize="30" />
                        <TextBlock Text="{Binding XPath=link}" FontSize="12" />
                        <Expander Header="Read..">
                            <TextBlock Text="{Binding XPath=./description}" TextWrapping="Wrap" TextTrimming="WordEllipsis" MaxWidth="520"/>
                        </Expander>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
</StackPanel>

The sample code looks almost similar to what we have already discussed. The major difference is how you parser the XML coming from the RSS feed. Here the XMLDataProvider points to an external Web address. The program once starts takes a second to load the rss from the external source. Once it is loaded, the specific nodes are bound to the Title, description and items shown on the ListBox.

Download Sample Application

I hope this would help you understanding how you could load your XML using Binding.
If you have any query, please let me know. Thanks for reading.

No comments:

Post a Comment

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.