Sunday 19 August 2007

Silverlight Downloader which works both with file system and online mode

One of the issues with the 1.1 Alpha Refresh for Silverlight is that if you attempt to use the downloader object when you are working from the local file system, it will throw up an exception. This forces you to work under IIS.

It is nice to work directly from the file system and skipping out IIS, but you want to develop your applications to use the downloaders from the beginning.

I have therefore created a little downloader which can be used for media elements (will not work for xaml, or xml documents), but will work great for images and videos.

This downloader class can work in multiple modes, if you are working under a file system, then it will just set the image, video sources directly for you (and won't use the downloader), if you specifiy a ZipFile it will download the zipfile for you (using the downloader (unless working in local mode, where it will use the local path and ignore the zip)), finally if you have multiple files to be downloaded (and don't want to use a zip file (large number of files to be displayed, and you wish to show them whenever they have downloaded, then this will also work for you).

The class declaration is below:



using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace Roskakori.Silverlight.Common.Controls
{
public class SchemeSensitiveDownloader
{
#region properties
private Downloader _mediaDownloader;
public string ZipFile { get; set; }
public List<FileDetails> Files { get; set; }
#endregion

#region Constructors
/// <summary>
/// Constructor
/// </summary>
public SchemeSensitiveDownloader()
{
// Initialise
Files = new List<FileDetails>();
}
#endregion

#region events
public event EventHandler DownloadCompleted;
public event EventHandler FileDownloadCompleted;
public event EventHandler FileDownloadProgressChanged;

/// <summary>
/// Download Completed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _mediaDownloader_Completed(object sender, EventArgs e)
{
// Check if we have anything attached to the event
if (FileDownloadCompleted != null)
{
// Raise the File Downloaded Completed Event
FileDownloadCompleted(sender, e);
}

// Get the sender as a downloader
Downloader downloader = (Downloader)sender;

// Check if we have anything attached to the event
if ((DownloadCompleted != null) && ((downloader.Name == "zip" || (Convert.ToInt32(downloader.Name) == Files.Count - 1))))
{
// Raise the File Downloaded Completed Event
DownloadCompleted(this, new EventArgs());
}
}

/// <summary>
/// Download Progress Changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _mediaDownloader_DownloadProgressChanged(object sender, EventArgs e)
{
// Check if we have anything attached to the event
if (FileDownloadProgressChanged != null)
{
// Raise the File Downloaded Progress Changed Event
FileDownloadProgressChanged(sender, e);
}
}
#endregion

/// <summary>
/// Download the files apporiately either as a zip, individually, or as one
/// </summary>
public void Download()
{
// Loop through all the files if we have a zip file, or if local
if (string.IsNullOrEmpty(ZipFile) || (System.Windows.Browser.HtmlPage.DocumentUri.Scheme.ToLower() == "file"))
{
// Initialise
int i = 0;

// Loop through all the files
foreach (FileDetails file in Files)
{
// File Download
if ((System.Windows.Browser.HtmlPage.DocumentUri.Scheme.ToLower() == "file") && (FileDownloadCompleted != null))
{
// Raise the File Downloaded Completed Event
FileDownloadCompleted(file, new EventArgs());

// Check if we have anything attached to the event
if (DownloadCompleted != null)
{
// Raise the File Downloaded Completed Event
DownloadCompleted(this, new EventArgs());
}
}
else if (FileDownloadCompleted != null)
{
// Initialise the downloader
_mediaDownloader = new Downloader();

// Set an identifier
_mediaDownloader.SetValue(Downloader.NameProperty, i.ToString());

// Add the event listener
_mediaDownloader.Completed += new EventHandler(_mediaDownloader_Completed);
_mediaDownloader.DownloadProgressChanged += new EventHandler(_mediaDownloader_DownloadProgressChanged);

// Open the downloader
_mediaDownloader.Open("GET", new Uri(file.Source, UriKind.RelativeOrAbsolute));

// Send the request
_mediaDownloader.Send();
}

// increment
i++;
}
}
else
{
// Initialise the downloader
_mediaDownloader = new Downloader();

// Set an identifier
_mediaDownloader.SetValue(Downloader.NameProperty, "zip");

// Add the event listener
_mediaDownloader.Completed += new EventHandler(_mediaDownloader_Completed);
_mediaDownloader.DownloadProgressChanged += new EventHandler(_mediaDownloader_DownloadProgressChanged);

// Open the downloader
_mediaDownloader.Open("GET", new Uri(ZipFile, UriKind.RelativeOrAbsolute));

// Send the request
_mediaDownloader.Send();
}
}

public class FileDetails
{
public string Source { get; set; }
public Control AssociatedControl { get; set; }
public string Filename
{
get
{
var uriParts = Source.Split('/');
return uriParts[uriParts.GetUpperBound(0)];
}
}
}
}
}


If you wish to see it in action you can look at Mix07UK Sample Site. Both an online demo and source is available.

No comments: