|
using System;
using System.Net;
using System.Windows;
using System.ComponentModel;
using System.Windows.Resources;
using System.Reflection;
using System.IO;
using System.Windows.Controls;
namespace SilverModule
{
/// <summary>
/// SilverModule Model and Controller
/// </summary>
public class ModuleMaker : INotifyPropertyChanged
{
/// <summary>
/// data binding event handler
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = delegate { };
/// <summary>
/// module content is instantiated and ready to render after download
/// </summary>
public event EventHandler<ModuleReadyEventArgs> ModuleContentReady = delegate { };
/// <summary>
/// internal WebClient instance to communicate with server for module downloading
/// </summary>
private WebClient _webClient = null;
/// <summary>
/// Data bind field to loading progress prompt or error message display
/// </summary>
private string _statusMessage = "";
public string StatusMessage
{
get { return _statusMessage; }
set { _statusMessage = value; PropertyChanged(this, new PropertyChangedEventArgs("StatusMessage")); }
}
/// <summary>
/// The assembly name only, no extension (.xap, or .dll), MUST be set before using other properties
/// Also assuming the package name is [ModuleName].xap and it locates at the same folder as where the loading Silverlight app (main xap) is
/// Also assuming the UserControl Type name implemented inside [ModuleName] is also the same as [ModuleName]
/// </summary>
private string _moduleName;
public string ModuleName
{
get
{
return _moduleName;
}
set
{
if (String.IsNullOrEmpty(value))
throw new ArgumentNullException("ModuleName should never be empty or null!");
if (value != _moduleName)
{//new module name is set, needs to start download
_moduleName = value;
StartToDownloadModule();
}
}
}
private string _moduleAssemblyName;
public string ModuleAssemblyName
{
get
{//if the assemply name is not set explicitly, use the ModuleName appended .DLL as default one
return (String.IsNullOrEmpty(this._moduleAssemblyName)) ? this.ModuleName + ".dll" : this._moduleAssemblyName;
}
set
{
this._moduleAssemblyName = value;
}
}
/// <summary>
/// optional property
/// to be loaded module path relative to the main XAP, start with "/" but NOT ended with "/"
/// </summary>
public string ModuleRelativePath { get; set; }
/// <summary>
/// optional property
/// if not set, will use ModuleName as Module Type Name
/// </summary>
private string _moduleTypeName;
public string ModuleTypeName
{
get
{//assuming the type name will be namespaceName[same as module name].className[same as module name]
return String.IsNullOrEmpty(_moduleTypeName) ? ModuleName + "." + ModuleName : _moduleTypeName;
}
set
{
_moduleTypeName = value;
}
}
/// <summary>
/// internal property
/// the downloading URL for the module, ready-only
/// </summary>
public string ModuleURL
{
get
{
if (String.IsNullOrEmpty(ModuleName))
throw new ArgumentNullException("ModuleName needs to be set before get ModuleURL");
//if relative path is not set, assuming the module will be at the same folder as where main app.xap is
string moduleFolder = String.IsNullOrEmpty(ModuleRelativePath) ? "" : ModuleRelativePath + "/";
return moduleFolder + ModuleName + ".xap";
}
}
/// <summary>
/// Write-only loading progress value, will update data bound field value
/// </summary>
public int LoadingProcess
{
set
{
if (value <= 2)
this.StatusMessage = "Start loading...";
else if (value >= 99)
this.StatusMessage = String.Format("Loading {0} done.", ModuleName);
else
this.StatusMessage = String.Format("Loading {0}: {1}%...", ModuleName, value);
}
}
/// <summary>
/// Write-only error message that will be shown
/// </summary>
public string Error
{
set
{
this.StatusMessage = String.Format("Failed to load {0}: {1}", ModuleName, value);
}
}
/// <summary>
/// private helper functions
/// </summary>
private void StartToDownloadModule()
{
if (null == _webClient)
{//initialize the downloader
_webClient = new WebClient();
_webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(onDownloadProgressChanged);
_webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(onOpenReadCompleted);
}
if (_webClient.IsBusy)
{//needs to cancel the previous loading
this.StatusMessage = "Cancelling previous downloading...";
_webClient.CancelAsync();
return;
}
Uri xapUrl = new Uri(this.ModuleURL, UriKind.RelativeOrAbsolute);
_webClient.OpenReadAsync(xapUrl);
}
private void onDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
LoadingProcess = e.ProgressPercentage;
}
private void onOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (null != e.Error)
{//report the download error
this.Error = e.Error.Message;
return;
}
if (e.Cancelled)
{// cancelled previous downloading, needs to re-start the loading
StartToDownloadModule();
return;
}
// Load a particular assembly from XAP
Assembly aDLL = GetAssemblyFromPackage(this.ModuleAssemblyName, e.Result);
if (null == aDLL)
{//report the assembly extracting error
this.Error = "Module downloaded but failed to extract the assembly. Please check the assembly name.";
return;
}
// Get an instance of the XAML object
UserControl content = aDLL.CreateInstance(this.ModuleTypeName) as UserControl;
if (null == content)
{//report the type instnatiating error
this.Error = "Module downloaded and the assembly extracted but failed to instantiate the custome type. Please check the type name.";
return;
}
//tell the event handler it's ready to display
ModuleContentReady(this, new ModuleReadyEventArgs() { ModuleContent = content } );
}
private Assembly GetAssemblyFromPackage(string assemblyName, Stream xapStream)
{
Assembly aDLL = null;
// Initialize
Uri assemblyUri = new Uri(assemblyName, UriKind.Relative);
StreamResourceInfo resPackage = new StreamResourceInfo(xapStream, null);
if (null == resPackage)
return aDLL;
StreamResourceInfo resAssembly = Application.GetResourceStream(resPackage, assemblyUri);
if (null == resAssembly)
return aDLL;
// Extract an assembly
AssemblyPart part = new AssemblyPart();
aDLL = part.Load(resAssembly.Stream);
return aDLL;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.