하늘높이의 프로그래밍 이야기

Using Silverlight and RSS to Build a Hero Bar with ASP.NET
 

Laurence Moroney

Updated: May 2007

Applies to:
   Silverlight
   ASP.NET

Summary: Learn how to use Microsoft Silverlight and RSS through ASP.NET to create a simple hero bar that is easily customizable and regenerated. (11 printed pages)

Contents

Introduction
Creating the XAML Template.
Using RSS
Building an ASP.NET Application to Generate XAML from the RSS Document
Managing the URLs
Rendering the Hero Banner in Silverlight

Introduction

We have all seen hero bars on our favorite websites—you know, the banner at the top of the site that rotates around new content and provides direct linkage to it? Did you know that it is easy to create a hero bar with Silverlight? Did you also know that it is just as easy to drive that hero bar content using RSS?

In this article, you'll see how to create a simple one that is easily customizable and can be regenerated simply by editing an RSS document. As such, you can have a hero bar that highlights new blog entries (where your blog is syndicated via RSS), and all you have to do to update the bar is create a new blog entry!

Figure 1 shows an example of a hero bar in action.

Figure 1. Viewing a hero bar in Internet Explorer

This article will guide you through the following steps in order to construct a hero bar:

  1. You will create an XAML template that contains one item and any necessary resources, such as animations (Creating the XAML Template.).
  2. You will create an ASP.NET application that reads an RSS file and generates XAML using the template in Step 1 (Building an ASP.NET Application to Generate XAML from the RSS Document).
  3. You will create a second ASP.NET application that reads an RSS file and generates JavaScript code containing the URLs (Managing the URLs).
  4. You will create an HTML page that contains the Silverlight control, sourcing it from the ASP.NET application in Step 2 and from the JavaScript generator in Step 3 (Rendering the Hero Banner in Silverlight).

Creating the XAML Template

The hero bar in Figure 1 is a 960 × 150 pixel bar containing an image, a headline element with a larger font, and a details element with a smaller font. In XAML, these are collected together into a canvas such as the following:

<Canvas Width="960" Height="150" x:Name="cnvItem0" Opacity="0" MouseLeftButtonDown="javascript:DoClick">
      <Canvas.Background>
         <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
            <GradientStop Color="#FF310909" Offset="0"/>
            <GradientStop Color="#FFAE0000" Offset="1"/>
         </LinearGradientBrush>
      </Canvas.Background>

<Image x:Name="img0" Width="344" Height="136"
       Canvas.Left="8" Canvas.Top="8" Source=""/>

<TextBlock x:Name="hdln0" Width="576" Height="40" 
           Canvas.Left="376" Canvas.Top="8"
           FontFamily="Tahoma" FontSize="24"
           FontWeight="Normal" Foreground="#FFFFFFFF"
           Text="Headline Text 1" TextWrapping="Wrap"/>

<TextBlock x:Name="detl0" Width="576" 
           Height="96" Canvas.Left="376" 
           Canvas.Top="48" FontFamily="Tahoma" 
           FontSize="14" FontWeight="Normal" 
           Foreground="#FFFFFFFF" 
           Text="Text Details 1 Describing the stuff inside the hero bar. Clicking anywhere on the bar should take us to the bar details page." 
           TextWrapping="Wrap"/>

</Canvas>

Of course, you can use any XAML design that you like, but do take note of the element names. These names are used by the ASP.NET code to fish out the nodes using XPath.

In addition to this, you will likely want an animation that manages the transition between different banners. In the following example, the animation used is a fade in opacity from one element to the next:

<Storyboard x:Name="FadeIn" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames x:Name="Step0"    
        Storyboard.TargetName="cnvItem0"     
        Storyboard.TargetProperty="(UIElement.Opacity)" >
      <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
      <SplineDoubleKeyFrame KeyTime="00:00:05" Value="1"/>
      <SplineDoubleKeyFrame KeyTime="00:00:06" Value="0"/>
  </DoubleAnimationUsingKeyFrames>
</Storyboard>

This example uses a DoubleAnimationUsingKeyFrames that fades the opacity of the item from 0 (invisible) to 1 (fully visible) over five seconds, and back to 0 over 1 further second. This will be used as the template for each animation. For example, if you have five elements on your hero bar, you will have five of these storyboards set up—one for each element.

Using RSS

The RSS specification defines an <item> node, which can contain a title, a link, a description, and a resource element such as a graphic or a video in an <enclosure> tag. This example uses images, but there is no reason why you couldn't use a video hero bar by specifying videos in the <enclosure> and using <MediaElement> instead of <Image> within your XAML.

The following is an example RSS document that contains links to Silverlight samples on Channel9, which you can update with any links you like.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="2.0"><channel>
  <title>W3Schools Home Page</title>
  <link>http://www.w3schools.com</link>
  <description>Free web building tutorials</description>
  <item>
    <title>Red v Blue, starring Scott Guthrie</title>
    <link>http://channel9.msdn.com/playground/wpfe/rvbplayer/</link>
    <description>ScottGu in Red v Blue. Can an executive shoot a gun? 
                 Can he do it again?</description>
    <enclosure 
        url="http://channel9.msdn.com/playground/wpfe/images/rvbplayer.jpg"
        length="10659" type="image/jpeg" />
  </item>
  <item>
    <title>Updated Grand Piano showing Keyboard input!</title>
    <link>http://channel9.msdn.com/playground/wpfe/grandpiano/</link>
    <description>Your chance to be the concert pianist 
                 you always wanted to be...</description>
    <enclosure 
        url="http://channel9.msdn.com/playground/wpfe/images/grandpiano.jpg"
        length="6809" type="image/jpeg" />
  </item>
  <item>
    <title>An online WPFE Pad</title>
    <link>http://channel9.msdn.com/playground/wpfe/wpfepad/</link>
    <description>A great little online notepad that allows 
                 you to write and test your XAML</description>
    <enclosure 
        url="http://channel9.msdn.com/playground/wpfe/images/wpfepad.jpg"
        length="10938" type="image/jpeg" />
  </item>
</channel>
</rss>

If you are using RSS that is generated from your blog (for example), make sure that these nodes are supported. If they are not, you will need to amend your ASP.NET code in order to handle the structure of your RSS document.

Building an ASP.NET Application to Generate XAML from the RSS Document

The first thing you'll want to do is override the HTML output from the ASPX page—you will just want the ASPX page to write out XAML. The most straightforward way is to delete all markup on the ASPX page, except for the first line. For example, if you named your page "GenerateXaml.aspx," your page should have a line like the following:

<%@ Page Language="C#" AutoEventWireup="true" 
 CodeFile="GenerateXaml.aspx.cs" Inherits="_Default" %>

You would then want to use code like the following on your Page_Load event handler:

protected void Page_Load(object sender, EventArgs e)
    {
        String strRSSDoc = Request.Params["feed"];
        if (strRSSDoc == null)
            strRSSDoc = Server.MapPath("rssfeed.xml");
        WebClient rssClient = new WebClient();
        Stream data = rssClient.OpenRead(strRSSDoc);
        StreamReader reader = new StreamReader(data);
        String sBuffer = reader.ReadToEnd();
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(sBuffer);
        XmlDocument xmlXaml = GenerateXaml(xmlDoc);
        Response.ContentType = "text/xml";
        Response.Write(xmlXaml.OuterXml);
    }

Because this code takes a feed parameter, you can pass in the URI of an RSS document by calling http://server/GenerateXaml.aspx?feed=URI. Or if you omit this parameter, it will read the data from a file called rssfeed.xml in the same directory as the ASPX page.

It then reads this RSS file into an XAML document and calls the GenerateXaml helper function to create a new XmlDocument called "xmlXaml." It then writes the "xmlXaml" contents out to the response stream.

The workhorse of this application is the aforementioned GenerateXaml helper function. It's a big function, so we'll go through it step by step.

The first thing you'll need to do is to create the following:

XmlDocument xmlXaml = new XmlDocument();
xmlXaml.Load(Server.MapPath("template.xml"));

// Set up the namespaces. These are necessary for XPathing an
// XML Document that contains multiple name spaces
// Note: The default namespace does not have a prefix, but
// in order to XPath it, we have to prefix it with one,
// so I use 'd' (for default)
NameTable myn = new NameTable();
XmlNamespaceManager mng = new XmlNamespaceManager(new NameTable());
mng.AddNamespace("d", 
        "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
mng.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");

When using XAML in ASP.NET with the XML APIs, you need to use an XmlNameSpaceManager to handle the different namespaces. Some elements in Silverlight use the default namespace, while others use the extended namespace prefixed with an "x:" (i.e. "x:Name"). You need to specify a prefix for the namespace manager when using a default namespace, so the "d" prefix is used. For example, when searching for nodes in the default namespace "Image" using XPath, you will refer to it as "d:Image."

Next, you'll get the list of item nodes from the RSS document. To do this, you will use the SelectNodes API to return a NodeList of items.

// The Hero bar items are stored in the RSS 'item' node
//Get a nodelist of the items.
XmlNodeList xnItems = rssFeed.SelectNodes("//item");

Now you'll want to iterate through this list and make copies of the XAML canvas for each node:

for (int lp = 0; lp < xnItems.Count; lp++)
{
  if (lp == 0)
  {
    itemCanvasTemplate = 
        xmlXaml.SelectSingleNode("//d:Canvas[@x:Name='cnvItem0']", mng);
  }
  else
  {
    XmlNode xNodeToCopy = 
        xmlXaml.SelectSingleNode("//d:Canvas[@x:Name='cnvItem0']", mng);
    itemCanvasTemplate = xNodeToCopy.Clone();
}

Now that you have your node, you’ll want to edit the details, to put the image, headline and text from the RSS Item:

// Now that we have our node, we will customize it with the details taken from the RSS Item.
//First, set up the variables holding the RSS items.
string strItemTitle = xnItems[lp].SelectSingleNode("title").InnerText;
string strItemLink = xnItems[lp].SelectSingleNode("link").InnerText;
string strItemDescription = 
    xnItems[lp].SelectSingleNode("description").InnerText;
string strItemPicture = 
    xnItems[lp].SelectSingleNode("enclosure").Attributes["url"].InnerText;

// Then, edit the node with these items directly
// 1. Edit the canvas to give it a unique ID
string strCanvasName = "cnvItem" + lp;
itemCanvasTemplate.Attributes["x:Name"].Value = strCanvasName;
            
// 2. Edit the Image Name and Source
XmlNode xNode = 
    itemCanvasTemplate.SelectSingleNode("//d:Image[@x:Name='img0']", mng);
string strImageName = "img" + lp;
xNode.Attributes["x:Name"].Value = strImageName;
xNode.Attributes["Source"].Value = strItemPicture;

// 3. Edit the Headline Textblock name and content
xNode = 
  itemCanvasTemplate.SelectSingleNode("//d:TextBlock[@x:Name='hdln0']", mng);
string strHeadlineName = "hdln" + lp;
xNode.Attributes["x:Name"].Value = strHeadlineName;
xNode.Attributes["Text"].Value = strItemTitle;

// 4. Edit the Details Texblock name and content
xNode = 
  itemCanvasTemplate.SelectSingleNode("//d:TextBlock[@x:Name='detl0']", mng);
string strDetailsName = "detl" + lp;
xNode.Attributes["x:Name"].Value = strDetailsName;
xNode.Attributes["Text"].Value = strItemDescription;

xmlXaml.DocumentElement.AppendChild(itemCanvasTemplate);

The process for cloning and editing the animation is very similar. You can see this in the code download for this article.

Managing the URLs

One small problem with XAML is that when you specify the JavaScript event handler for the page, you cannot parameterize it. Thus, you cannot put the individual URI for an element in the hero banner into your XAML like this:

MouseLeftButtonDown="javascript:DoClick(MyURI)"

To instead determine the URI, you will have to call a generic DoClick function and use the ID of the canvas that raised the event. A second ASPX page will read the RSS and generate a JavaScript array. The page containing the Silverlight banner can then reference this and the JavaScript event handler will use this JavaScript array.

The following is the C# code to write out a JavaScript array:

XmlNodeList xnItems = xmlDoc.SelectNodes("//item");

Response.Write("var urls = new Array()\n");

for (int lp = 0; lp < xnItems.Count; lp++)
{
  string strItemLink = xnItems[lp].SelectSingleNode("link").InnerText;
  Response.Write("urls[" + lp + "]='" + strItemLink + "';\n");
}

And here is an example of a JavaScript array that it writes out:

var urls = new Array()
urls[0]='http://channel9.msdn.com/playground/wpfe/rvbplayer/';
urls[1]='http://channel9.msdn.com/playground/wpfe/grandpiano/';
urls[2]='http://channel9.msdn.com/playground/wpfe/wpfepad/';

Rendering the Hero Banner in Silverlight

Now that you have all the pieces in place, it is a simple matter to render the hero banner using Silverlight.

The complete code for an HTML page that implements it, along with the JavaScript to handle the URLs follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html  >
<head>
    <title>Untitled Page</title>
    <script type="text/javascript" src="js/silverlight.js"></script>
    <script type="text/javascript" src="js/createSilverlight.js"></script>
    <script type="text/javascript" src="GenerateJS.aspx"></script>
    <script type="text/javascript">
        function DoClick(sender,args)
        {
            var n = sender.name.replace(/cnvItem/,"");
            window.open(urls[n]);
        }
    </script>
</head>
<body>
<div id='slControlHost'>
<script type="text/javascript">
    createSilverlight();
</script>   
</div>
</body>
</html>

Notice the reference to the GenerateJS.aspx page is a <script> reference. This will call the GenerateJS.aspx page, which in turn generates a JavaScript array (as in the previous section).

The <Canvas> elements in the XAML specifies that DoClick should handle the mouse left button down, and this function is implemented here. It creates n, a new var. It also sets it to the value of the sender, replacing the string cnvItem with an empty string.

The sender contains the name of the canvas that raised the event, such as cnvItem0, cnvItem1. Replacing cnvItem with an empty string then assigns n to 0 or 1 in these cases. Then, to navigate to a URL specified in the urls array (generated by GenerateJS.aspx), you use Window.Open(urls[n]).

Finally, it sets up the Silverlight control using the call with createSilverlight(). This is present in the createSilverlight.js javascript library that was included at the top of the page. This contains the instantiation code for the Silverlight control that you can see here:

function createSilverlight()
{  
    Sys.Silverlight.createObject("GenerateXaml.aspx", 
        slControlHost, "slControl1",
        {width:'960', height:'150', inplaceInstallPrompt:true, 
         background:'black', isWindowless:'true', 
         framerate:'24', version:'0.8'
        },
        {onError:null, onLoad:null},
        null);
}

The first parameter is GenerateXaml.aspx, which generates the XAML as we saw earlier. Silverlight then renders it. As such, you'll now have a hero banner on your page, which you can easily amend using different XAML, and easily update by updating your RSS.

This shows how Silverlight fits nicely into the overall developer ecosystem of Microsoft tools—using RSS, ASP.NET, XAML and Silverlight to mash-up a new application!


신고

COMMENT :0

티스토리 툴바