大家知道,XAP文件是Silverlight 2(本文所使用版本为Beta 2)应用程序编译打包后的一个文件,包括了Silverlight 2应用程序所需的一切文件,
如程序集、资源文件等。这就带来了一个问题,在整个系统中肯定有很多个XAP文件,不可能把所有的应用都打包到一个XAP文件中,而每个应用都
包含了其需要的一切文件,包括程序集和资源,这不可避免的的会带来重复下载问题,某一些公用的程序集会被所有的XAP文件打包,而不同的XAP是
不能共享依赖程序集的,就是说即使2个XAP在一个页面中引用,且两个XAP都包含了很多相同的程序集引用,也会都同时下载,如果把一个XAP文件的去
掉,则不能正常运行,这里要注意的是在运行时的内存里同一个进程中相同的程序集只有一份,这里没搞懂XAP文件的运行机制,既然同一页面的一
个XAP把公用程序集都下载下来了,且已装载,而另一个XAP还是不能直接使用。这就要求每个XAP文件都要自包含所引用的一切资源,导致每个XAP文
件都比较大,引起重复下载,影响性能。
为了解决每个应用XAP文件的大小,让其只包含自身的逻辑处理,而不重复包含公用部分,采用如下的部署结构可以解决这个问题,如下图:
整个系统由一个主框架XAP文件承载,在主框架XAP文件中动态引用其他XAP文件中的类,通过反射创建实例,测试证明,这种方式系统认为被引用的XAP文件中
类是和主框架XAP在同一个上下文环境,可以访问主框架的公用程序集。这样被引用的XAP文件中就不需要包含公用程序集了,从而大大减小了XAP文件的大小。
采用这种方式需要把应用XAP文件中公用程序集删除,并修改AppManifest.xaml文件,删除对公用程序集的引用。下面提供一个动态加载其他XAP文件中的类的
示例实现:
/// <summary>
/// 从XAP文件中动态装载指定的程序集
/// 此方法引用于如下文章:
/// http://www.cnblogs.com/Terrylee/archive/2008/07/10/access-usercontrol-in-external-xap-file-from-silverlight-2.html
/// </summary>
public static 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();
Deployment deployment = (Deployment)XamlReader.Load(appManifestString);
Assembly assembly = null;
foreach (AssemblyPart assemblyPart in deployment.Parts)
{
if (assemblyPart.Source == assemblyName)
{
String source = assemblyPart.Source;
StreamResourceInfo streamInfo = Application.GetResourceStream(
new StreamResourceInfo(packageStream,
"application/binary"),
new Uri(source, UriKind.Relative));
assembly = assemblyPart.Load(streamInfo.Stream);
break;
}
}
return assembly;
}
/// <summary>
/// 一个工具方法,就象导航到某个页面一样,导航到指定的XAP文件和具体的类
/// 可根据自己的需要实现
/// </summary>
public static void NaveOtherXap(UIElement parent, string xapname, string classname)
{
WebClient wc = new WebClient();
//确定需要引用的XAP文件的路径
Uri uri = new Uri(GetRootUrlContext("",0)+"xxxx/silverlight/demo/"+xapname+".xap");
wc.OpenReadCompleted+=new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
wc.OpenReadAsync(uri);
}
/// <summary>
/// 异步事件方法
/// </summary>
static void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
//xxxx.dll为引用的XAP文件中的程序集名称,可以考虑XAP文件和这个引用的程序名称按某种
//规则定义
Assembly assembly = LoadAssemblyFromXap(e.Result, "xxxx.dll");
//创建指定的类
UIElement element = assembly.CreateInstance("className") as UIElement;
Page p = Application.Current.RootVisual as Page;
UserControl qd = element as UserControl;
qd.VerticalAlignment = VerticalAlignment.Stretch;
qd.HorizontalAlignment = HorizontalAlignment.Stretch;
p.LayoutRoot.Children.Clear();
p.LayoutRoot.Children.Add(qd);
}
期待在正式版中微软已决这个问题,不用自己来解决这个问题。