Windows Presentation Foundation (WPF) and AOL Video Search
by Shawn Wildermuth
March 16, 2007
Introduction
No one tell Google, but there are internet videos on sites other than YouTube (and GoogleVideo). Since everyone and their brother has started their own video website since the success of YouTube, it would be good if there was a way to search for just videos. Oh wait, there is: AOL Video Search. What's most interesting to me is that AOL Video Search is doing video search across engines. One search can yield results from YouTube, CBS, NBC, etc. No more trying to remember which site had that cool video of the exploding whale--a quick search will help you find it on several sites.
After my last article, in which I showed you how to add video search to your ASP.NET website, I got to thinking that it should be really easy to make a quick Windows Presentation Foundation (WPF) application using the API. Here is what the resulting application will look like:

Figure 1. The Video Library API
Starting a WPF Project
For this article, we will do everything in Visual Studio. Assuming you have installed the .NET 3.0 framework, the updated Windows SDK, and the Visual Studio Extensions for WPF, you will be able to create a new Windows Application (WPF). This project type sets up an application that uses a single window. All the work we will be doing will be in the Window1.xaml file and its code-behind file (Window1.xaml.cs).
Let's start with the design markup for our video searcher application. A new WPF window starts with
a top-level Window element and contains a simple Grid element:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="VideoLibrary.Window1"
x:Name="mainWindow"
Title="AOL Video Searcher"
Width="800" Height="600" >
<Grid>
</Grid>
</Window>
For our specific purpose, the Grid container makes the most sense. We will
need to determine how our layout should be created on the grid. By breaking out
the UI into a grid as seen in Figure 2, we can see that we need three rows and two
columns:

Figure 2. The grid
Now that we see what we want, let's make it happen by adding the row and column definitions to our XAML:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="38" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
In the row and column definitions, we are able to define specific widths for some
of the elements, and use an asterisk (*) to indicate "filling" of the available
area that remains. The ColumnDefinitions code above specifies that our left column should always be 250 wide and the second column should occupy the rest of the space. Likewise, the RowDefinitions code specifies that the top and bottom rows are fixed sized, with the middle row occupying whatever space remains in the window.
Now that we have the grid set up, we need to put some content in it. First we need
the top banner. This banner is made up of a background rectangle with a color
gradient, a TextBlock containing the title, and a stack panel containing the search
elements. Each of these elements need to be tied to the row and columns they will use, as seen below:
<!-- Top Frame -->
<Rectangle Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="LightGray" Offset="0" />
<GradientStop Color="SteelBlue" Offset=".6" />
<GradientStop Color="Silver" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Label FontSize="20" FontWeight="Bold"
Margin="0,1,0,3"
Grid.Column="0" Grid.ColumnSpan="2">AOL Video Search</Label>
<!-- Search Box -->
<StackPanel Orientation="Horizontal" Grid.Column="1"
HorizontalAlignment="Right">
<Label FontSize="16" Margin="0,1,0,3"
VerticalAlignment="Bottom" >Search:</Label>
<TextBox Name="searchBox"
Margin="0,9,9,6" MinWidth="150"
HorizontalAlignment="Stretch" />
<Button Margin="0,9,9,6" >Search</Button>
</StackPanel>
Notice that the Grid.Column and Grid.Row attributes are attached to the each of these
elements to specify where in the grid they should live. On the background gradient
rectangle, you will notice a Grid.ColumnSpan attribute that specifies that the
rectangle should span across both columns of our design.
Next, we need a list box to show each result. A ListBox element allows you
to specify the template for how to show the data, but for now we will just place
it in the grid and come back after we have searched for videos. We also need
to place a Frame element in the grid. The Frame element allows for different
types of content to be placed. If the Source of a Frame is a valid URI, it
will show the result as a web page. We will use it to show our actual resulting
videos. The ListBox and Frame should look like this:
<!-- Results Pane -->
<ListBox Name="resultBox" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="1" />
<!-- Video Pane -->
<Frame Name="videoFrame"
Grid.Row="1" Grid.Column="1" />
Lastly, we need to create our bottom frame. Again, we are going to use a spanning rectangle and a stack panel:
<!-- Bottom Frame -->
<Rectangle Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="SteelBlue" Offset="0" />
<GradientStop Color="LightGray" Offset=".6" />
<GradientStop Color="SteelBlue" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
Grid.ColumnSpan="2" Grid.Row="2" Margin="0,0,9,0">
<TextBlock FontSize="12" FontWeight="Bold" Text="Total Found: "/>
<TextBlock FontSize="12" />
</StackPanel>
Searching for Videos
The Video Search API has not changed since the last article. We will continue
to use the getVideos call on the XML API. Again in this article, I will be using
YOURAPPID as the API key. You will need to replace this string with your actual
application ID before the example will work.
In this example we will be using some of the same code from the ASP.NET example
in that we will continue to call a PerformSearch method that will construct the URL
to do our search. The big difference in this example is that we will let data
binding do all our work for us. In the ASP.NET example, we not only constructed
the URL, but we executed it and converted the result into a form that we could use.
Instead of doing all that work, we can use an XmlDataProvider element
to data bind across all the elements in our window design. An XmlDataProvider
is placed inside the resources of the window itself to allow us to use it throughout the window. To bind to it, we will need
to specify a key to use to refer to it (e.g., x:Key). In this case we are going to
call it SearchResult:
<Window
...
>
<Window.Resources>
<!-- XML Data Source -->
<!-- We're binding directly to the search API Results -->
<XmlDataProvider x:Key="SearchResult">
</XmlDataProvider>
</Window.Resources>
...
</Window>
Normally an XmlDataProvider specifies a source of where the XML comes from (or it could be a data island inside the XAML). But we are going to construct the search URI in code, so we can leave the provider contents blank. To construct the search URI, we can use almost the same code we did in the last article. Our PerformSearch method
will construct the request URL based on the search term. In the earlier example,
we used the Server object to encode our search term for the URL. Since we
are not using ASP.NET, we will need to use a class called HttpUtility that contains
a UrlEncode method (in fact, the same code that the Server object exposed). Before
we can use this class, we will need a reference to the System.Web assembly.
Another change to our PerformSearch method is to remove all the code that actually
performs the search for us. We can simply comment out all the code after the
construction of the request URL. Finally, we need to set our XmlDataProvider source
to be the request URL we just created. We can set the source by retrieving
the XmlDataProvider from the resources as seen at the end of the PerformSearch method
below:
void PerformSearch()
{
const string appId = "YOURAPPID"; // Your AppID here const
// string method = "truveo.videos.getVideos";
const string method = "truveo.videos.getVideos";
const int pageSize = 50;
// Construct the Search and Search URL
string searchTerm = HttpUtility.UrlEncode(searchBox.Text);
string requestUrl =
string.Format("http://beta.searchvideo.com/apiv3?appid={0}&method={1}&query={2}&results={3}",
appId,
method,
searchTerm,
pageSize);
// We don't need any of this code because we can ask WPF
// to use an XML DataSource and data binding to do
// all the real work.
// Perform an Synchronous Search
//HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
//WebResponse response = req.GetResponse();
// The Stream of the Search Response
//Stream strm = response.GetResponseStream();
// Deserialize the results into our XSD Generated Class
//XmlSerializer ser = new XmlSerializer(typeof(Aol.Search.Video.Response));
//Response res = (Response)ser.Deserialize(strm);
// If there are results, then show them
//theDataList.DataSource = res.VideoSet.Video;
//theDataList.DataBind();
// Show the number of results
//numResultsLabel.Text = string.Format("Found {0} result(s)",
// res.VideoSet.totalResultsAvailable);
// Change the Source of the XML Data Provider
XmlDataProvider xmlData = (XmlDataProvider)this.Resources["SearchResult"];
xmlData.Source = new Uri(requestUrl);
}
Data Binding the Search
When you execute a search with the Search API, it returns an XML document that looks something like this (I've omitted unnecessary parts of the document):
<?xml version="1.0" encoding="utf-8"?>
<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://beta.searchvideo.com"
xsi:schemaLocation="http://beta.searchvideo.com apiv3.xsd">
<method>truveo.videos.getVideos</method>
<query>baby kungfu</query>
<VideoSet>
...
</VideoSet>
</Response>
Of particular note is the xmlns attribute on the Response tag. This
attribute specifies the default namespace. Because there is a default namespace,
we have to tell the XmlDataProvider about the namespace so that our
XPath expressions work. Unfortunately, we cannot tell the XmlDataProvider
that there is a default namespace. Instead, we have to specify a prefix. Inside the
XmlDataProvider, you will need to add an XmlNamespaceCollection
inside the XmlDataProvider.NamespaceManager property like so:
<!-- XML Data Source -->
<!-- We're binding directly to the search API Results -->
<XmlDataProvider x:Key="SearchResult">
<XmlDataProvider.XmlNamespaceManager>
<XmlNamespaceMappingCollection>
<XmlNamespaceMapping Uri="http://beta.searchvideo.com" Prefix="aol" />
</XmlNamespaceMappingCollection>
</XmlDataProvider.XmlNamespaceManager>
</XmlDataProvider>
Now that we have our XmlDataSource set up, we can start binding data. We should bind
the entire Grid to the data source so we can do bindings across the
entire user interface. To do this, add the DataContext attribute to
the Grid:
<Grid DataContext="{StaticResource SearchResult}">
Let's make sure our search is working correctly. To do so, we should start with a simple binding.
In the footer of the XAML, there is a TextBlock that holds the number
of results. It's the last TextBlock in the XAML. We can set the Text
of that TextBlock using an XPath expression. In this case, we want to
find the total results, which can be reached with the XPath of "/aol:Response/aol:VideoSet/aol:totalResultsAvailable". We can bind that text box as shown below:
<TextBlock FontSize="12"
Text="{Binding XPath=/aol:Response/aol:VideoSet/aol:totalResultsAvailable}" />
To test to see if the bindings are working, we need to go to the button and add an event handler for the Click event. You can do this by adding a Click attribute to the button in the header:
<Button Margin="0,9,9,6" Click="search_Clicked">Search</Button>
In the code-behind, you will want to create the handler:
public void search_Clicked(object source, RoutedEventArgs args)
{
PerformSearch();
}
If you run the application, put in a result, and press the button you should see the number of results appear at the end of the page.
Completing the Application
Now that we have all the wiring hooked up, we need to simply add the rest of the
data binding to the application. First, the ListBox we created earlier to show the
results on the left side of the user interface needs to be bound. To do this, we
first need to set the entire ListBox to be bound to the list of videos returned.
You can do this by binding the ItemsSource to the list of videos:
<!-- Results Pane -->
<ListBox Name="resultBox" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="1"
ItemsSource="{Binding XPath=/aol:Response/aol:VideoSet/aol:Video}" />
Next we need to define a DataTemplate for each item in the ListBox.
Data templating is too large a topic to explain here (but there is a link to a good article on MSDN in the References
section below). In a nutshell, a DataTemplate is a set of XAML that is used for each item in the
ListBox. As it binds to individual pieces of XAML, the DataTemplate will be
used to create the ListBox item. We use data binding in the template to create a thumbnail of the
video, the title of the video, and other information about the video, as seen below:
<!-- Template for the list box -->
<DataTemplate x:Key="videoTemplate">
<Grid HorizontalAlignment="Stretch"
ToolTip="{Binding XPath=aol:description}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" MaxWidth="100"/>
<ColumnDefinition Width="120" MaxWidth="120"/>
</Grid.ColumnDefinitions>
<TextBlock FontSize="14" FontWeight="Bold"
Width="235" ClipToBounds="True"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
Text="{Binding XPath=aol:title}" />
<Image Source="{Binding XPath=aol:thumbnailUrl}"
Width="100" Height="50"
Grid.Row="1" Grid.Column="0" Grid.RowSpan="3"
HorizontalAlignment="Left" />
<TextBlock Grid.Row="1" Grid.Column="1"
ClipToBounds="True"
Text="{Binding XPath=aol:channel}" />
<TextBlock Grid.Row="2" Grid.Column="1"
ClipToBounds="True"
Text="{Binding XPath=aol:dateProduced}" />
<TextBlock Grid.Row="3" Grid.Column="1"
ClipToBounds="True"
Text="{Binding XPath=aol:userRating}" />
</Grid>
</DataTemplate>
You will notice that when we data bind individual elements, we do not use the entire
XPath path, but only the relative path. This is because each list box item will
be passed the element of Video from the resulting XML file. The thumbnailUrl,
channel, title, and other data bound properties are all child elements of the Video
element, so we can bind to them by just specifying their names (with the namespace
prefix).
The DataTemplate is stored in the Window's resources like the XmlDataProvider
was. In this way we can refer to it from the ListBox by specifying the ItemTemplate
like so:
<!-- Results Pane -->
<ListBox Name="resultBox" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="1"
ItemsSource="{Binding XPath=/aol:Response/aol:VideoSet/aol:Video}"
ItemTemplate="{StaticResource videoTemplate}" />
Finally, we can bind our Frame element to the selected item of the
ListBox. We do this by specifying an ElementName in the
binding to the Source of the Frame element. The ElementName
allows us to bind to other controls in the XAML document. The final step to make this work
is to specify a complex path (note: not XPath but path, since we're
dealing with simple CLR types instead of XML elements). This path is going to get
the SelectedItem of the ListBox, and then get the videoUrl
element of the selected Video node. Finally, we can finish the
Path with the InnerText of the the videoUrl element
to specify the source of the Frame.
<!-- Video Pane -->
<Frame Name="videoFrame"
Source="{Binding ElementName=resultBox, Path=SelectedItem[videoUrl].InnerText}"
Grid.Row="1" Grid.Column="1" />
Conclusion
Using WPF's native XML data binding makes creating your own video search application quite simple. Creating a Windows application that allows searching for videos on the internet becomes a fairly trivial affair. Because the AOL Video Search API is a simple URL that returns XML, you can let WPF data binding do all the heavy lifting instead of parsing out the results by hand and creating controls.
Resources
- Source code: The example project
References
- AOL Video Search: The Video Search API documentation
- "Building a Simple AOL Video Search API Application Using Ajax": An introduction to the Video Search API
- "Using the AOL API with ASP.NET, Part 1: AOL Video Search": Using video search in ASP.NET
- DataTemplating Overview: The MSDN documentation
- "Windows Presentation Foundation Data Binding, Part 1": An article about WPF data binding
- "Windows Presentation Foundation Data Binding, Part 2": An article about WPF data binding
- Programming WPF: The RTM Edition: Book by Chris Sells and Ian Griffiths

