Microsoft Silverlight and Truveo Video Search
by Kirk Evans
September 14, 2007
When building web-based applications, you often have to make a compromise between creating high-quality, engaging user experiences and the amount of coding effort required to build those applications. Microsoft Silverlight makes it easy to build engaging media experiences and rich internet applications (RIAs). In this article, we will show how to leverage the Truveo Video Search API using Microsoft Silverlight.
What Is Silverlight?
The official description of Silverlight (from the Silverlight home page) is: "Microsoft Silverlight is a cross-browser, cross-platform plugin for delivering the next generation of .NET-based media experiences and rich interactive applications for the Web. It offers a flexible programming model that supports AJAX, VB, C#, Python, and Ruby, and integrates with existing web applications. Silverlight supports fast, cost-effective delivery of high-quality video to all major browsers running on the Mac OS or Windows." My unofficial description is that it is the coolest thing to happen to the browser since the XMLHTTPRequest object. And yes, you read that official description correctly: Silverlight works with multiple browsers, such as Opera, Safari, Mozilla, and Internet Explorer, and runs on both Windows and the Mac OS.
As stated before, Silverlight is just a plugin to your browser that knows how to render XAML documents, and XAML documents are just XML documents that Silverlight knows how to parse. This has large implications for the ability of search engines to locate and index content in your Silverlight applications because the data is not hidden in an opaque file. XAML is little more than a serialization format, and Silverlight understands a subset of what the Windows Presentation Foundation understands (for more on WPF, see Shawn Wildermuth's article on Windows Presentation Foundation (WPF) and AOL Video Search). The abstraction of low-level coding functionality into higher-order markup provides greater developer productivity and richer tool integration. A key differentiator for Silverlight is that it is integrated with the DOM model, meaning that you can use the same JavaScript programming tools and experiences without investing in new tools.
Getting Started with Silverlight
To get started, you will need to download the Silverlight 1.0 browser plugin as well as the Silverlight 1.0 SDK, available at www.silverlight.net. The browser plugin will allow you to see your XAML markup rendered as vector graphics in the browser, and the SDK provides the tools necessary to build Silverlight applications. All you need to build the rest of the application is a simple text editor (although using a tool like Microsoft Visual Studio 2008 will greatly reduce the amount of code necessary to write Silverlight applications).
Throughout the rest of this article, we will build a Silverlight application that calls Truveo's video search API using Ajax and client-side technologies. The application is shown below:

Figure 1. Screenshot of Truveo Silverlight video search application
A working version of this demo is available at kaevans.sts.winisp.net/Shared%20Documents/AOL%20Video%20Search/Default.html. Let's see how to build this application by looking at the contents of the Default.html document.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>AOL Silverlight Video Search</title>
<script type="text/javascript"
src="http://xml.truveo.com/TruveoVideoSearchAPIv3.js"></script>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="VideoSearch.js"></script>
<link href="styles/Stylesheet1.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="truveoLogo">
<img src="images/t_logo.gif" alt="Truveo Logo" />
</div>
<div id="criteria">
Enter search criteria:
<input id="Text1" type="text" />
<input id="Button1" type="button" value="Search AOL Video!" />
</div>
<div id="SilverlightPlugInHost">
<script type="text/javascript">
createSilverlight();
</script>
</div>
<div class="silverlightLogo">
<img src="images/logo.jpg" alt="Silverlight logo"/>
</div>
</body>
</html>
There are several parts of this HTML document that we want to call out. The first is the line:
<script type="text/javascript" src="http://xml.truveo.com/TruveoVideoSearchAPIv3.js"></script>
This line imports the JavaScript library that represents the Ajax API for Truveo's video search. By importing the JavaScript into our file, we avoid nasty things like server-side cross-domain bridges or ActiveX "click to activate" object warnings. The next line to notice:
<script type="text/javascript" src="Silverlight.js"></script>
This line imports the Silverlight.js library, which is part of your solution. This file is included in the Silverlight 1.0 SDK, you need to be sure to include it as part of your project. Since this is a script file that we are importing from the SDK, we are going to leave this file alone and place any customizations into another file, VideoSearch.js:
<script type="text/javascript" src="VideoSearch.js"></script>
The final bit in this document that we want to highlight is the script block containing a call to a function, createSilverlight:
<script type="text/javascript">
createSilverlight();
</script>
The createSilverlight function is something you need to implement. We will implement this function, and others, in our custom VideoSearch.js script file. We will show the entire VideoSearch.js script file in a bit, but for now, let's just look at the createSilverlight custom function:
function createSilverlight(){
Silverlight.createObjectEx({
source: 'Scene.xaml', //The source XAML document
//The ID of the HTML element that declares the plugin
parentElement: document.getElementById('SilverlightPlugInHost'),
id: 'SilverlightPlugIn', //a unique ID to refer to the plugin
properties: {
width: '400',
height: '400',
background:'#ffffffff',
isWindowless: 'false',
version: '0.8'
},
events: {
onError: null,
onLoad: null
},
context: null
});
}}
The parts of this function to note (we will reference them again later) are the source and id parameters. The source points to a XAML document that contains the UI in an XML representation that Silverlight understands, and the id field provides a means for us to reference and use the Silverlight control from within our application. Note that we are writing everything from scratch here, when typically you would use a project template in a tool such as Microsoft Expression Blend or Microsoft Visual Studio. There are project templates available for both Visual Studio 2005 and Visual Studio 2008 that automate the creation of the HTML and JavaScript files for Silverlight applications, but we are going to show how to use any text editor to build a Silverlight application. After all, it's just XML, JavaScript, and HTML.
A Look at XAML and Silverlight
Before we go any further building our JavaScript functions, let's work on the UI portion a bit. The HTML page will be loaded (just like any normal browser application), which calls the JavaScript function createSilverlight that we just wrote. The createSilverlight function points to an XML file, scene.xaml. The name of the file is not reserved; you can name it whatever you want, just make sure that the name of the file and the source argument in the createSilverlight function match. We will show the entire Scene.xaml file in a bit, but for now let's just look at the main content for clarity. Scene.xaml contains some basic markup:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
Background="White"
x:Name="Page"
RenderTransformOrigin="0,0"
>
<Canvas x:Name="canvas0">
<TextBlock x:Name="text0" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image0" Width="100" Height="100"/>
</Canvas>
...
</Canvas>
The root element of an XAML file is the Canvas element, which is bound to thehttp://schemas.microsoft.com/client/2007 namespace. The root Canvas element may have child elements of the type Canvas, which serve as named containers of other elements. In this example, we refer to the Canvas element by name, canvas0; it contains an image and a text block. The text block will contain text returned from Truveo's API, and the image will contain a thumbnail representation of the video.
Using Truveo's Ajax Video Search API
To obtain the data that is presented back to the user, we need to call the Truveo video search API. The documentation is available on dev.aol.com and contains several easy-to-use examples. We will leverage one of those examples:
window.attachEvent("onload", pageLoad);
var TVS = null;
function pageLoad()
{
window.detachEvent("onload", pageLoad);
window.attachEvent("onunload", pageUnload);
document.getElementById("Button1").attachEvent("onclick", Button1_onclick);
TVS = new TruveoVideoSearch('1x1jhj64466mi12ia');
TVS.attachEvent("onupdate", "handleUpdate();");
TVS.initialize();
}
function handleUpdate()
{
var slplugin = document.getElementById("SilverlightPlugIn");
for (var i=0; i < TVS.VideoSet.totalResultsReturned; i++)
{
slplugin.content.findName("image" + i).Source =
TVS.VideoSet.Video[i].thumbnailUrl;
slplugin.content.findName("text" + i).Text =
TVS.VideoSet.Video[i].title;
}
}
function pageUnload()
{
window.detachEvent("onload", pageUnload);
}
In this example, we are creating a global variable, TVS, that will contain the results of the Truveo Video Search. We attach to the onload event of the Window object, and provide initialization within our custom pageLoad method. We also attach a click handler to our HTML button, and initialize the Truveo video search object. When results are returned from the search API, our handleUpdate method is called, which in turn populates the UI elements in our Silverlight XAML document, setting the image Source and the textbox Text properties with the returned values.
Responding to User Input
To access the Silverlight elements within JavaScript, we refer to the Silverlight plugin control using the ID parameter specified within our createSilverlight() JavaScript function. Once we have a handle to that object, we use the Silverlight API to locate specific objects and set their properties. For example, to set the image location for a specific image, we could use the following line of code:
var slplugin = document.getElementById("SilverlightPlugIn");
slplugin.content.findName("text2").Text = "Hello, World!";
Now for the cool part. Not only do we want to set properties of the user interface elements from JavaScript, but we also want to react to changes in the user interface using the same programming model: JavaScript and the HTML DOM. We can wire up event handlers in our XAML document to our JavaScript functions. There are events for MouseEnter, MouseLeave, MouseLeftButtonDown, and MouseLeftButtonUp. There are nine Canvas elements, each containing its own TextBlock and Image controls, and we suffix the name of each with its numeric position to easily reference the elements from code later. The full Scene.xaml file is shown below.
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
Background="White"
x:Name="Page"
RenderTransformOrigin="0,0"
>
<Canvas x:Name="canvas0" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text0" Width="100" Height="100"
Canvas.ZIndex="1" TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image0" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas1" Canvas.Left="103" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text1" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image1" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas2" Canvas.Left="204" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text2" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image2" Width="100" Height="100" />
</Canvas>
<Canvas x:Name="canvas3" Canvas.Left="304" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text3" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image3" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas4" Canvas.Left="403" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text4" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image4" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas5" Canvas.Top="125" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text5" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image5" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas6" Canvas.Left="103" Canvas.Top="125" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text6" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image6" Width="100" Height="100"/>
</Canvas>
<Canvas x:Name="canvas7" Canvas.Left="204" Canvas.Top="125" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text7" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image7" Width="100" Height="100" />
</Canvas>
<Canvas x:Name="canvas8" Canvas.Left="304" Canvas.Top="125" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text8" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image8" Width="100" Height="100" />
</Canvas>
<Canvas x:Name="canvas9" Canvas.Left="403" Canvas.Top="125" MouseEnter="mouse_enter"
MouseLeave="mouse_leave" MouseLeftButtonDown="mouse_down">
<TextBlock x:Name="text9" Width="100" Height="100" Canvas.ZIndex="1"
TextWrapping="Wrap" Visibility="Collapsed"/>
<Image x:Name="image9" Width="100" Height="100" />
</Canvas>
</Canvas>
Since we defined the events that are to be handled from within the UI, we now implement them within our JavaScript file, VideoSearch.js. The full script implementation is shown below.
window.attachEvent("onload", pageLoad);
var TVS = null;
function createSilverlight()
{
Silverlight.createObjectEx({
source: 'Scene.xaml', //The source XAML document
//The ID of the HTML element that declares the plugin
parentElement: document.getElementById('SilverlightPlugInHost'),
id: 'SilverlightPlugIn', //a unique ID to refer to the plugin
properties: {
width: '400',
height: '400',
background:'#ffffffff',
isWindowless: 'false',
version: '0.8'
},
events: {
onError: null,
onLoad: null
},
context: null
});
}
function pageLoad()
{
window.detachEvent("onload", pageLoad);
window.attachEvent("onunload", pageUnload);
document.getElementById("Button1").attachEvent("onclick", Button1_onclick);
TVS = new TruveoVideoSearch('1x1jhj64466mi12ia');
//TVS.attachEvent("onload", "handleVSLoad();");
TVS.attachEvent("onupdate", "handleUpdate();");
TVS.initialize();
}
function Button1_onclick()
{
for(var i=0;i<10;i++)
{
var slplugin = document.getElementById("SilverlightPlugIn");
slplugin.content.findName("image" + i).Source = null;
slplugin.content.findName("text" + i).Text = "";
slplugin.content.findName("url" + i).Text = "";
}
TVS.getVideos(document.getElementById("Text1").value);
}
function handleUpdate()
{
var slplugin = document.getElementById("SilverlightPlugIn");
for (var i=0; i < TVS.VideoSet.totalResultsReturned; i++)
{
slplugin.content.findName("image" + i).Source =
TVS.VideoSet.Video[i].thumbnailUrl;
slplugin.content.findName("text" + i).Text =
TVS.VideoSet.Video[i].title;
}
}
function pageUnload()
{
window.detachEvent("onload", pageUnload);
}
function mouse_enter(sender, args)
{
var slplugin = document.getElementById("SilverlightPlugIn");
var id = sender.Name.replace("canvas","");
slplugin.content.findName("text" + id).Visibility="Visible";
slplugin.content.findName("image" + id).Opacity="0.4";
}
function mouse_leave(sender, args)
{
var slplugin = document.getElementById("SilverlightPlugIn");
var id = sender.Name.replace("canvas","");
slplugin.content.findName("text" + id).Visibility="Collapsed";
slplugin.content.findName("image" + id).Opacity="1.0";
}
function mouse_down(sender, args)
{
var slplugin = document.getElementById("SilverlightPlugIn");
var id = sender.Name.replace("canvas","");
window.open(TVS.VideoSet.Video[id].videoUrl);
}
In each mouse event, we know which Canvas element was responsible for raising the event, because we are passed a reference in the sender argument. Using our clever naming convention, we can easily figure out which TextBlock and Image control to reference by stripping out "Canvas" from the argument name, leaving us with the index of the elements that we need to reference. The TVS.VideoSet object contains the results of the video search; we can use that to open a new browser window with the correct video search URL.
See, I told you this part was cool.Not only can we react to events in the user interface, but we can set properties of the Silverlight elements as well. Note that the mouse_enter and mouse_leave handlers contain code for setting the opacity of an image, stuff that would be more difficult with JavaScript alone. In our handlers, we are setting the opacity of the image to 40 percent and making the text description of the video search result visible. The effect is pretty cool: mouse over a video search result image, and it will become pale, with the text overlaying the image. When you click on one of the video search result items, a new browser window is opened that points back to Truveo's video player. You can see a working version of this demo at
kaevans.sts.winisp.net/Shared%20Documents/AOL%20Video%20Search/Default.html.
Conclusion
To build an improved user experience, we simply needed to leverage an existing Ajax API and create an XML document. There are no special compilers or development tools required. I built this application using Visual Studio 2008 only because the JavaScript Intellisense and debugging capabilities made it easier for me to write the code and fix errors more quickly.
I hope that you see just how easy it is to build applications using Microsoft Silverlight, and how easy the Ajax API for Truveo's video search is to use. In the next article of this three-part series, we will dive into sprucing the demo up a bit with custom animations.
Resources
The source code for this article is available online on my SharePoint site.
References
- Silverlight.net QuickStarts: QuickStarts for learning how to get up and running with Silverlight
- Truveo 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
- Windows Presentation Foundation (WPF) and AOL Video Search: Using video search with WPF
