Have you seen the Silverlight? – More Silverlight

Dynamic Content

This article was originally published in VSJ, which is now part of Developer Fusion.

Downloading content

You’ll often want to pull down content, be it XAML, images or media. In many cases you can simply set the Source property of the relevant control or element, but what happens if you want some finer-grained control over the downloading process? Fortunately, Silverlight includes a Downloader object to do the heavy lifting for you. Let’s take a quick look at how you might use it to download a video, in this case whenever the user clicks the Load button.

We’re aiming for a nice (at least to the limits of my graphical capabilities) download bar, as shown in Figure 2.

Figure 2
Figure 2: A simple progress bar

To achieve this effect we can show a Rectangle and adjust its Width as the download progresses. The code for this is shown in the following listing:

<Canvas ...>
    ...
    <MediaElement x:Name=”thePlayer”
    	... />
    <Canvas x:Name=”progressBar”
    	Visibility=”Hidden”
    	Canvas.Top=”413”
    	Canvas.Left=”272”>
    	<Rectangle Stroke=”#FF0A358C”
    		StrokeThickness=”2”
    		Width=”204” Height=”30”
    		RadiusX=”10” RadiusY=”10” />
    	<Rectangle Width=”0”
    		Canvas.Top=”2” Height=”28”
    		x:Name=”progressRect”
    		Canvas.Left=”2”
    		RadiusX=”8” RadiusY=”8”>
    		<Rectangle.Fill>
    			<LinearGradientBrush
    				StartPoint=”0,0”
    				EndPoint=”1,0”>
    				<GradientStop
    			Color=”Blue” Offset=”0”/>
    				<GradientStop
    		Color=”Purple” Offset=”1”/>
    			</LinearGradientBrush>
    		</Rectangle.Fill>
    	</Rectangle>
    </Canvas>
</Canvas>

The progress bar consists of a Canvas that contains a couple of Rectangles that will be used to provide the outline and the fill of the bar. To implement the bar, we need to show the canvas and then adjust the width of the filled rectangle to reflect the download progress. All that is required once the media file has been downloaded is to hide the Canvas.

The key to the whole download mechanism is the Downloader object. This both performs the download and raises events to indicate its progress and to indicate that the download is complete. This is clearly very similar to making an XmlHttpRequest download in AJAX.

The full code to perform the media download is shown below:

handleMouseUp: function(
    sender, eventArgs)
{
    var downloader = sender.getHost().
    	createObject( “downloader” );
    downloader.addEventListener(
    	“downloadProgressChanged”,
    	Sys.Silverlight.createDelegate(
    this, this.onProgressChanged ) );
    downloader.addEventListener(
    	“completed”,
Sys.Silverlight.createDelegate( this,
    	this.onDownloadCompleted ) );
    sender.findName( “progressBar”
    	).visibility = “Visible”;
    downloader.open( “GET”,
    	“http://localhost/mediasite/
    	handler.ashx?movie=brushes”,
    	true );
    downloader.send();
},

onProgressChanged: function(
    sender, eventArgs )
{
    var progressRect = sender.findName(
    	“progressRect” );
if( sender.downloadProgress <= 1.0 )
    	progressRect.width =
    sender.downloadProgress * 200.0;
},

onDownloadCompleted: function(
    sender, eventArgs )
{
    sender.findName( “progressBar” ).
    	visibility = “hidden”;
    sender.findName( “progressRect” ).
    	width = 0.0;
    sender.findName( “thePlayer” ).
    	setSource( sender, “” );
},
...

The handleMouseUp method is called in response to the user clicking the Load button. This method uses the Silverlight control’s createObject() method to create the Downloader object. In fact, in Silverlight 1.0 this is the only type of object that you can create with createObject().

We then connect up the two main events of the Downloader so that we can report progress, before commencing the download. One thing to be aware of is that the Visibility property of an element is not a Boolean, but one of three values: hidden, visible or collapsed.

In the onProgressChanged event handler the width of the progress rectangle is changed to reflect the percentage that’s been downloaded. There’s only one thing to watch out for here: the downloadProgress value returned by the Downloader object will be in the range 0 to 1, unless the content-length header has not been set by the server. In this case, it will return infinity, which is not a legal value for the width of a rectangle!

Finally, in the onDownloadCompleted event handler we hide the Canvas that contains all the progress bar information and then set the Source property on our MediaElement. The setSource() method takes a reference to the Downloader, plus the name of a the part that should be used, which should be set to “” when only a single file (rather than a .zip file) has been downloaded.

As you can appreciate, the Downloader object offers functionality that’s very similar to making a standard AJAX callback.

Dynamic content

One of the joys of Silverlight is the way that you can dynamically create and alter content. Again, this is something that’s being done increasingly with AJAX applications, but I find that Silverlight is just that little bit easier.

Let’s start with a simple client-only example. Figure 3 shows an updated version of the page, which now includes a facility.

Figure 3
Figure 3: Dynamically loading XAML

This is perhaps not the sort of feature that you’d want to provide in a typical media player, but it certainly shows how flexible the XAML scene can become.

<script type=”text/javascript”>
<!--
    function loadXAML()
    {
    	var control =
    		document.getElementById(
    		“SilverlightControl” );
    	var xamlFragment =
    		document.getElementById(
    		“txtXAML” ).value;
    	var elem =
    	control.content.createFromXAML(
    		xamlFragment );
    	var btn =
    		control.content.findName(
    		document.getElementById(
    			“selectTarget”).value );
    	btn.fill = elem;
    }
// -->
</script>
...
<textarea id=”txtXAML” ... />
<select id=”selectTarget”>...</select>
<input id=”btnLoadXAML” type=”button”
value=”Load” onclick=”loadXAML();” />
...

As you can see, the code in the listing merely extracts the value from the textarea and uses it to create some elements from the XAML, which it then sets as the fill for the selected button. Clearly, this assumes that the user enters valid XAML for a Brush, such as a SolidColorBrush or LinearGradientBrush.

Note that it will rarely make sense to allow the user to enter XAML directly, but the purpose of this code was really to show you how to create XAML on the client and add it into the current scene.

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.” - Jamie Zawinski