Silverlight 动态加载XAP文件
本文根据网上资源整理而成,主要讲述两种动态加载Silverlight生成后的XAP文件的方法,实现按需下载减小传输文件的目的。
前置说明:
本文例子用VS2012编写,解决方案中有三个项目,一个Web应用程序,两个Silverlight应用程序(不是类库,类库在生成时默认不会生成独立的XAP包),如下图
1、方法一,直接将需要的XAP文件下载到本地内存
说明:这种方式,每次从服务器获得的XAP文件都是最新的,如果服务器端的XAP文件有所更改,客户端也会马上显示出来
根据例子来讲解,SlLogin.xap是程序运行时默认加载的XAP文件,SilverlightPartXap.xap是点击SlLogin项目中Login页面上的登录按钮后加载的XAP文件,并将新加载的XAP文件中的UI界面显示出来,Login.xaml后台主要源码如下(Login.cs):
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Resources; using System.Xml.Linq; namespace SlLogin { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } //登录 private void btnLogin_Click(object sender, RoutedEventArgs e) { Uri mainXapUri = new Uri("SilverlightPartXap.xap",UriKind.Relative); WebClient webClient = new WebClient(); webClient.OpenReadCompleted += webClient_OpenReadCompleted; webClient.OpenReadAsync(mainXapUri);//获取另一个xap文件 } void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { Stream mainXapStream = e.Result; Assembly mainAssembly = LoadAssemblyFromXap(mainXapStream, "SilverlightPartXap.dll"); UIElement mainFrame = mainAssembly.CreateInstance("SilverlightPartXap.MainPage") as UIElement; this.Content = mainFrame; } /// <summary> /// 从XAP中获取程序集 /// </summary> /// <param name="packageStream"></param> /// <param name="assemblyName"></param> /// <returns></returns> Assembly LoadAssemblyFromXap(Stream packageStream, String assemblyName) { Stream stream = Application.GetResourceStream( new StreamResourceInfo(packageStream, null), new Uri("AppManifest.xaml", UriKind.Relative)).Stream; String appManifestString = new StreamReader(stream).ReadToEnd(); //Linq to xml XElement deploymentRoot = XDocument.Parse(appManifestString).Root; List<XElement> deploymentParts = (from assemblyParts in deploymentRoot.Elements().Elements() select assemblyParts).ToList(); Assembly asm = null; foreach (XElement xElement in deploymentParts) { string source = xElement.Attribute("Source").Value; AssemblyPart asmPart = new AssemblyPart(); asmPart.Source = source; StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(packageStream, "application/binary"), new Uri(source, UriKind.Relative)); if (source == "SilverlightPartXap.dll") { asm = asmPart.Load(streamInfo.Stream); } else { asmPart.Load(streamInfo.Stream); } } return asm; } } }
2.方法二,使用silverlight的独立存储区来存放从服务器动态加载的XAP文件,这样只要独立存储区的内容还存在,它就会使用独立存储区的内容,而不去从服务器重新加载,但得不到新的XAP,一旦服务器的XAP修改了,也不会立马显示,源码如下:
using System; using System.Collections.Generic; using System.IO; using System.IO.IsolatedStorage; using System.Linq; using System.Net; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Resources; using System.Xml.Linq; namespace SlLogin { public partial class NLogin : UserControl { public NLogin() { InitializeComponent(); } //登录 private void btnLogin_Click(object sender, RoutedEventArgs e) { using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) { if (!store.FileExists("SilverlightPartXap.xap")) { WebClient c = new WebClient(); c.OpenReadCompleted += new OpenReadCompletedEventHandler(c_OpenReadCompleted); c.OpenReadAsync(new Uri("SilverlightPartXap.xap", UriKind.Relative)); } else { LoadData(); } } } void c_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) { System.IO.IsolatedStorage.IsolatedStorageFileStream fileStream; // create the file fileStream = store.CreateFile("SilverlightPartXap.xap"); // write out the stream to isostore WriteStream(e.Result, fileStream); fileStream.Close(); } LoadData(); } private void WriteStream(Stream stream, System.IO.IsolatedStorage.IsolatedStorageFileStream fileStream) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) { fileStream.Write(buffer, 0, bytesRead); } } private void LoadData() { using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) { IsolatedStorageFileStream fileStream = store.OpenFile("SilverlightPartXap.xap", FileMode.Open, FileAccess.Read); #region Original Code StreamResourceInfo sri = new StreamResourceInfo(fileStream, "application/binary"); Stream manifestStream = Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream; string appManifest = new StreamReader(manifestStream).ReadToEnd(); //Linq to xml XElement deploymentRoot = XDocument.Parse(appManifest).Root; List<XElement> deploymentParts = (from assemblyParts in deploymentRoot.Elements().Elements() select assemblyParts).ToList(); Assembly asm = null; foreach (XElement xElement in deploymentParts) { string source = xElement.Attribute("Source").Value; AssemblyPart asmPart = new AssemblyPart(); asmPart.Source = source; StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(fileStream, "application/binary"), new Uri(source, UriKind.Relative)); if (source == "SilverlightPartXap.dll") { asm = asmPart.Load(streamInfo.Stream); } else { asmPart.Load(streamInfo.Stream); } } UIElement myData = asm.CreateInstance("SilverlightPartXap.MainPage") as UIElement; this.Content = myData; #endregion } } } }