Navigate back home
GalaSoft Laurent Bugnion
Silverlight: Downloading Zipped files with the WebClient (stand Silverlight 2 beta 1)

Introduction

In the "old" alpha edition of Silverlight, you could use the Downloader class to download a zip file containing one or many packed media elements (images, videos). The Downloader provided a progress report (to update a progress bar, for example). After the download was completed, you could use the Image.SetSource or MediaElement.SetSource method to directly unpack one file from the downloaded zip file.

In Silverlight 2 beta, the interfaces changed, but you can still do the same operations. Let's see how:

Creating

<?xml version="1.0" encoding="utf-8" ?> <mediafiles> <mediafile type="video" name="mov2008021202.wmv"/> <mediafile type="video" name="mov2008021203.wmv"/> <mediafile type="image" name="el2008021001.jpg"/> <mediafile type="image" name="el2008021101.jpg"/> <mediafile type="image" name="el2008021103.jpg"/> <mediafile type="image" name="el2008021501.jpg"/> </mediafiles>

Designing the XAML UI

<UserControl x:Class="SilverlightApplication1.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:Name="LayoutRoot" Background="White"> <Image x:Name="MyImage" /> <MediaElement x:Name="MyVideo" /> <TextBlock x:Name="ProgressTextBlock" Text="Init" Margin="5,0,0,0" /> <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Opacity="0.5" Orientation="Horizontal" Margin="0,0,0,5" MouseEnter="StackPanel_MouseEnter" MouseLeave="StackPanel_MouseLeave"> <Button Content="Prev" x:Name="PrevButton" Click="PreviousButton_Click" Height="30" Margin="0,0,5,0" Width="80" Opacity="1" Cursor="Hand" IsEnabled="False" /> <Button Click="NextButton_Click" x:Name="NextButton" Height="30" Margin="0,0,5,0" Width="80" Opacity="1" Content="Next" Cursor="Hand" IsEnabled="False" /> </StackPanel> </Grid> </UserControl>

This XAML code contains an Image and a MediaElement, used to display images and videos. It has a TextBlock to display the download progress. And two buttons in a StackPanel, to display the Previous and Next media.

Declaring attributes

private List<MediaInfo> _mediaInfos = null; private StreamResourceInfo _zipInfo = null; private int _mediaIndex = 0;

The attribute _mediaInfos will contain the list of media information read from the XML file. The attribute _zipInfo stores the StreamResourceInfo read from the Zip file. Finally, the _mediaIndex stores the index of the media file currently displayed by the application.

Starting the download

public Page() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Page_Loaded); }
void Page_Loaded(object sender, RoutedEventArgs e) { WebClient webClient = new WebClient(); webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted); webClient.OpenReadAsync(new Uri("../Media.zip", UriKind.Relative)); }
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { ProgressTextBlock.Text = "Downloading " + e.ProgressPercentage + "%"; }

Reading the XML file

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { if (e.Error != null) { ProgressTextBlock.Text = "Error: " + e.Error.Message; return; } ProgressTextBlock.Text = "Loading"; _zipInfo = new StreamResourceInfo(e.Result, null); // Read manifest from zip file StreamResourceInfo manifestInfo = Application.GetResourceStream(_zipInfo, new Uri("content.xml", UriKind.Relative)); StreamReader reader = new StreamReader(manifestInfo.Stream); XDocument document = XDocument.Load(reader); var mediaFiles = from m in document.Descendants("mediafile") select new MediaInfo { Type = (MediaType) Enum.Parse(typeof(MediaType), m.Attribute("type").Value, true), Name = m.Attribute("name").Value }; _mediaInfos = new List<MediaInfo>(); _mediaInfos.AddRange(mediaFiles); ProgressTextBlock.Visibility = Visibility.Collapsed; PrevButton.IsEnabled = true; NextButton.IsEnabled = true; DisplayMedia(_mediaInfos[0]); }

Displaying the media

private void DisplayMedia(MediaInfo mediaInfo) { StreamResourceInfo mediaStreamInfo = Application.GetResourceStream(_zipInfo, new Uri(mediaInfo.Name, UriKind.Relative)); switch (mediaInfo.Type) { case MediaType.Image: MyImage.Visibility = Visibility.Visible; MyVideo.Visibility = Visibility.Collapsed; BitmapImage image = new BitmapImage(); image.SetSource(mediaStreamInfo.Stream); MyImage.Source = image; break; case MediaType.Video: MyImage.Visibility = Visibility.Collapsed; MyVideo.Visibility = Visibility.Visible; MyVideo.SetSource(mediaStreamInfo.Stream); MyVideo.Play(); break; } }

Additional Enum and Class

public enum MediaType { Video = 0, Image = 1, } public class MediaInfo { public MediaType Type { get; internal set; } public string Name { get; internal set; } }

Conclusion

This code demonstrates how easy it is to pass a Zip file containing various media files to a Silverlight application. In a few lines of code, we have a full blown downloader (including download progress indication), and a UI displaying mixed videos and images. The beauty of it is that all the information needed is contained in a XML file, so you can change the content of the Zip file without recompiling the application. It also shows how to use LINQ to XML to load a XML file in a very concise and easy way.

Download and Demo
Date Version Description
23.03.2008 V1.0.0 First published (stand Silverlight 2 beta 1).