joemarini.com

Amazon WishWatch: Data Styling in XAML

Article Summary: Demonstrates an all-XAML way to read data from an XML data source and display it using a technique called "Data Styling". Data Styling is Avalon's method of applying an appearance and structure to a given data object, whether it is an XML node, CLR object, or other type of data object.

In this example, Data Styling is used to display the contents of a particular Amazon Wish List.

UPDATE: This example was updated Feb 15, 2005 for the public Avalon CTP Build

download Download the code for this tutorial

In my last article, I showed how to build a simple application to read data from an RSS feed and display it in a window using 100% XAML. In this article, I'm going to use a similar technique to display data from Amazon's public XML data feed using Avalon's Data Styling, in which styles can be automatically applied to records of data. The application reads a person's Amazon Wish List and displays the results in a scrollable list. Each of the items in the list represents a subset of the XML data returned from the Amazon service.

Oh, and once again - no C# code required.

If you're an MSDN subscriber and you have the Avalon CTP Build installed on your machine (NOT the PDC Build), then you can download the code for this sample and try it out yourself. You'll need to get your own Amazon Developer ID and Token, which takes about 5 minutes on Amazon's web services section.

The Amazon WishWatch Application

The WishWatch application runs in an Explorer window when you double-click its icon in the Longhorn desktop:

Screenshot of XAML Amazon Wish List Reader in Longhorn

(click for larger version)

In this case, WishWatch is looking at my personal Amazon wish list. As you can tell from the screen shot, I'm a fan of Diana Krall and Eric Clapton, and I'm also hoping that someone might send me a USB storage key. Each of the items in the list receives its data from the XML result that Amazon's service returns when given a particular person's wish list ID. In addition, each of the items is represented by the same XAML style definition, with the appropriate values from the XML substituted in the right places. To top it all off, you can click on the "Click Here to Go To This Item" URL Link for each item to be taken directly to that item's page on Amazon, should you wish to purchase that particular item for the person.

How WishWatch Works

Like Bloghorn, the Amazon WishWatch application defines an XML data source from which it gets its information. In this case, the XML source accesses Amazon's public web services API. It then creates a few user interface elements to present the data to the user, and wires everything together using Longhorn's data-binding mechanism to create a respnsive, data-driven UI.

That's where the similarity ends, however. Recall that in the Bloghorn example, each item in the RSS feed list was explicitly styled by setting the Listbox' ItemStyle attribute to point to the style to use for each item. In WishWatch, that style association is performed automatically by the Avalon Data Binding engine. To get this to happen is pretty easy - you simply name a style with the same name as the corresponding XML element. When the control that is bound to a data source is formatting its items, it uses that style to represent the corresponding data record.

Examining The Code

The code for WishWatch comes together in about 70 or so lines of XAML:

<DockPanel xmlns="http://schemas.microsoft.com/2003/xaml" xmlns:def="Definition">
  <DockPanel.Resources>
    <XmlDataSource XPath="ProductInfo" def:Name="AmazonWishData"
      Source="http://xml.amazon.com/onca/xml3?t=joemarinicom-20&amp;dev-t=YOUR_TOKEN_HERE&amp;WishlistSearch=2YLYHTQL2CSKG&amp;type=lite&amp;f=xml" />

    <Style def:Name="Details">
      <Style.VisualTree>
        <Border DockPanel.Dock="Top" Margin="0 5 0 5" BorderThickness="2"
              BorderBrush="#999999">
        <DockPanel DockPanel.Dock="Top" def:StyleID="listItem">
        <Border DockPanel.Dock="Top" Background="#777777">
          <Text Width="100%" FontSize="18" TextContent="*Bind(XPath=ProductName)"
                Foreground="White"/>
        </Border>

        <DockPanel Margin="5 5 5 5" DockPanel.Dock="Left" Width="200">
          <Image Source="*Bind(XPath=ImageUrlMedium)"/>
        </DockPanel>

        <DockPanel DockPanel.Dock="Right">
          <FlowPanel DockPanel.Dock="Top">
            <Text FontSize="14" Margin="0 0 8 0" TextContent="Catalog Category: "
                FontWeight="Bold"/>
            <Text FontSize="14" TextContent="*Bind(XPath=Catalog)" />
          </FlowPanel>
          <FlowPanel DockPanel.Dock="Top">
            <Text FontSize="14" Margin="0 0 8 0" TextContent="ASIN: "
                FontWeight="Bold"/>
            <Text FontSize="14" TextContent="*Bind(XPath=Asin)" />
          </FlowPanel>
          <FlowPanel DockPanel.Dock="Top">
            <Text FontSize="14" Margin="0 0 8 0" TextContent="List Price: " FontWeight="Bold"/>
            <Text FontSize="14" TextContent="*Bind(XPath=ListPrice)" TextDecorations="StrikeThrough"/>
          </FlowPanel>
          <FlowPanel DockPanel.Dock="Top">
            <Text FontSize="14" Margin="0 0 8 0" TextContent="Our Price: " Foreground="Green"
                 FontWeight="Bold"/>
            <Text FontSize="14" TextContent="*Bind(XPath=OurPrice)" Foreground="Green"/>
          </FlowPanel>
          <FlowPanel DockPanel.Dock="Top">
            <Text FontSize="14" Margin="0 0 8 0" TextContent="Availability: " FontWeight="Bold"/>
            <Text FontSize="14" TextContent="*Bind(XPath=Availability)"/>
          </FlowPanel>
          <HyperLink DockPanel.Dock="Top" NavigateUri="*Bind(XPath=@url)">
              <Text Width="500" FontSize="14" TextContent="Click Here to Go To This Item"
                  TextDecorations="Underline"/>
          </HyperLink>
        </DockPanel>
        </DockPanel>
        </Border>
      </Style.VisualTree>
    </Style>
    <Style def:Name="ItemsControlStyle">
      <ItemsControl />
      <Style.VisualTree>
        <FlowPanel DockPanel.Dock="Top" ItemsControl.IsItemsHost="true"/>
      </Style.VisualTree>
    </Style>
  </DockPanel.Resources>

  <DockPanel.DataContext>
    <Bind DataSource="{AmazonWishData}" />
  </DockPanel.DataContext>

  <FlowPanel DockPanel.Dock="Top">
    <Text FontSize="24" Height="30" TextContent="Joe's Wish List Currently Contains:" HorizontalAlignment="Center" VerticalAlignment="Center" />
  </FlowPanel>

  <ScrollViewer Margin="0 10 0 0" Width="100%">
    <ItemsControl Style="{ItemsControlStyle}" DockPanel.Dock="Top">
      <CollectionContainer Collection="*Bind(XPath=*)"/>
    </ItemsControl>
  </ScrollViewer>
</DockPanel>

Notice that, like Bloghorn, there is no C# code-behind for this file - everything is accomplished directly in the XAML markup.

The XmlDataSource tag at the beginning of the file establishes a connection to the Amazon public XML data feed, which can return a variety of information depending on what type of search is requested. WishWatch requests a particular wish list by specifying the appropriate wish list ID number as the value of the WishListSearch parameter in the URL string. This XML feed returns an array of XML nodes that contain data about the requested wish list. The nodes that we are interested in are the "Details" nodes, which contain data about the each individual wish list item.

Next, the code defines a style named "Details", which matches the name of the XML elements that we are interested in. Each element in the style is then bound to various parts of the Details XML element using XPath statements that are relative to the parent Details node. For example, each Details element contains three different URLs to use for the item's image - ImageUrlSmall, ImageUrlMedium, and ImageUrlLarge. To show a medium-size picture of the item, the style defines an Image object and binds the path for the image source to the ImageUrlMedium tag, which is a direct child of the Details tag. Similarly, the Click Here hyperlink is bound to the URL attribute of the Details tag itself by specifying the XPath expression @url as the binding path for the NavigateUri property.

The rest of the code is very similar to the Bloghorn code, except that WishWatch is using an ItemsControl to list the items in the wish list instead of a Listbox, since we didn't need each item in the list to be selectable. An ItemsControl is just a generic control that takes a collection of items and lays them out according to a given style definition, which is specified in the ItemsControlStyle. This style just directs the ItemsControl to use a simple FlowPanel as its layout manager. The ItemsControl is then wrapped inside a ScrollViewer to provide scrolling functionality.

All that is left to do is set the DataContext of the DockPanel that contains everything to the Amazon XML feed, bind it to the ItemsControl's CollectionContainer, and that's it.

Running the Application

Since Longhorn has the ability to run XAML code just by double-clicking the XAML file in the Windows Explorer, there's nothing special that has to be done to run WishWatch - you just double-click it and go. If, on the other hand, the application contained any code such as C#, it would first be necessary to build the finished executable using MSBuild or another tool like Visual Studio.

NOTE: To run this application you will need to get your own developer ID and token from Amazon. This takes less than 5 minutes on their web site - just go to Amazon's web services section.

When WishWatch starts up, the XmlDataSource connects to the Amazon public XML feed using my Developer ID and Developer Token, both of which I was able to get from the Amazon site within about 5 minutes. The Avalon Data BInding engine then handles the rest.

Conclusion

Avalon's Data Styling mechanism provides a very simple way to assign a visual appearance to abstract data, and can be used not only with XML, but with CLR objects and other data sources. In this example, we used Data Styling to display the contents of an Amazon wish list, however, this principle can be used to format any arbitrary data. end of article

download Download the code for this tutorial (NOTE: you need to have the Avalon CTP Build installed to run this sample. You can download this directly from MSDN. You will also need to supply your own Amazon Developer Token).

For information about how to obtain permission to re-publish this material, please contact us at info@joemarini.com.