技巧:在Silverlight中如何访问外部xap文件中UserControl

概述

众所周知,在Silverlight 2开始每个项目编译后都会打包成为一个xap文件,如果我们要访问当前xap文件中的UserControl比较容易,那我们如何访问一个外部xap文件中的内容呢?甚至于如何访问一个互联网上的xap文件呢?

本文将简单介绍一下在Silverlight中如何访问外部xap文件。

需求

现在我们先来看一下需求,大致是这样子的,在服务端我们有两个xap文件,其中MainProject.xap文件将会在MainProjectTestPage.aspx中引用,而ExternalProject.xap文件中的UserControl将会在MainProject.xap文件中访问,并进行显示,如下图所示:

TerryLee_0107

现在我们来建立相关的项目,最终完成的项目结构如下图所示:

TerryLee_0108 

这样在编译后,将会在ClientBin文件夹下产生两个.xap文件,现在我们将在MainProject.xap文件中访问ExternalProject.xap中的UserControl。

分析

在实现这个过程中,我们将会遇到两个问题:

1.因为没有任何页面引用ExternalProject.xap文件,所以它不会下载到客户端,这一点我们可以通过编码的方式来下载它。

2.访问ExternalProject.xap中的UserControl,我们需要找到对应的程序集,以便使用反射,我们知道在xap文件是一个标准的zip文件,它会包含相关的程序集(接下来我会写一篇文章专门解释xap文件),如下图所示:

TerryLee_0109

现在解决了xap文件的下载已经程序集的访问问题,我们可以着手来实现了。

实现

实现的过程也是相当简单,首先我们使用WebClient去下载xap文件,相信大家都知道该怎么做了,如下代码所示

void myButton_Click(object sender, RoutedEventArgs e)
{
    Uri address = new Uri("http://localhost:4161/ClientBin/ExternalProject.xap");
    WebClient webClient = new WebClient();
    webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
    webClient.OpenReadAsync(address);
}

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    // 得到下载结果
}

这一步比较简单,接下来我们将根据下载的结果,得到相应的程序集。我们知道在xap文件中的AppManifest.xaml文件相当于一个清单,列出了当前xap文件用到的程序集(下篇文章将会介绍),它的内容如下所示:

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            EntryPointAssembly="ExternalProject" 
            EntryPointType="ExternalProject.App" 
            RuntimeVersion="2.0.30523.6">
  <Deployment.Parts>
    <AssemblyPart x:Name="ExternalProject" Source="ExternalProject.dll" />
  </Deployment.Parts>
</Deployment>

注意,在Deployment.Parts节点下包含了当前应用程序中所有的程序集。首先要根据下载的结果获取AppManifest.xaml文件中的内容,如下代码所示:

Stream stream = Application.GetResourceStream(
        new StreamResourceInfo(packageStream, null),
        new Uri("AppManifest.xaml", UriKind.Relative)).Stream;

String appManifestString = new StreamReader(stream).ReadToEnd();

有了AppManifest.xaml中内容,就可以根据它来构造一个Deployment对象,Deployment对象提供了当前应用程序的Part和本地化信息清单,它的定义如下所示:

TerryLee_0110

注意它定义了一个很重要的属性Parts,通过该属性我们就可以访问所有Deployment中的程序集。好了,现在我们看如何通过AppManifest.xaml中的内容构造Deployment对象,以及遍历其中的程序集,如下代码所示:

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;

注意,在遍历时如果我们找到程序集名等于我们想要访问的程序集,则直接返回该程序集。最终完整的LoadAssemblyFromXap方法代码如下:

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;
}

得到程序集后,再使用反射创建相关的实例,并在页面上加载,如下代码所示:

Assembly assembly = LoadAssemblyFromXap(e.Result, "ExternalProject.dll");

UIElement element = assembly.CreateInstance("ExternalProject.SubPage") as UIElement;
this.holder.Children.Add(element);

运行后效果如下图所示:

TerryLee_0111 

跨域访问

在上面的示例中,不涉及到跨域(我会专门写一篇文章介绍)调用的问题,如果大家想访问的xap文件与当前xap文件不在同一站点中,需要添加跨域访问文件,如下代码所示:

clientaccesspolicy.xml:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*" />
      <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

总结

本文介绍了在Silverlight中如何访问外部xap文件这一技巧,希望对大家有所帮助。示例代码下载:

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2008-07-10 22:10 TerryLee 阅读(3873) 评论(37)  编辑 收藏 所属分类: Silverlight

  回复  引用  查看    
#1楼 2008-07-10 23:36 | Anytao      
头一次坐沙发,不成想是你的:-)
  回复  引用  查看    
#2楼 [楼主]2008-07-11 00:54 | TerryLee      
@Anytao
“第一次”给了我,中午请你吃饭,呵呵^_^
  回复  引用    
#3楼 2008-07-11 09:05 | jisen007 [未注册用户]
很rm!
  回复  引用    
#4楼 2008-07-11 09:09 | Jeffrey Chen [未注册用户]
学习了!!!!
  回复  引用  查看    
#5楼 2008-07-11 09:15 | Windie Chai(笑煞天)      
很好,很强大。
  回复  引用  查看    
#6楼 2008-07-11 09:19 | hxm      
每次silvierhgt站 出new webcast terrylee就出新的解说

真是好啊。。。每次都能看到中文的 感动!
  回复  引用  查看    
#7楼 [楼主]2008-07-11 09:47 | TerryLee      
@jisen007
“RM”?
  回复  引用  查看    
#8楼 [楼主]2008-07-11 09:47 | TerryLee      
@Jeffrey Chen
:)
  回复  引用  查看    
#9楼 [楼主]2008-07-11 09:47 | TerryLee      
@Windie Chai(笑煞天)
呵呵...
  回复  引用    
#10楼 2008-07-11 09:48 | Bamboo_wan [未注册用户]
接着写接着写。。。
太崇拜了~~
  回复  引用  查看    
#11楼 [楼主]2008-07-11 09:48 | TerryLee      
@hxm
?Silverlight网站有关于这个的WebCast吗?我怎么没看到呢?
  回复  引用  查看    
#12楼 [楼主]2008-07-11 09:48 | TerryLee      
@Bamboo_wan
呵呵,放心,最近在使用Silverlight中的一些心得、技巧等我都会分享出来的。
  回复  引用    
#13楼 2008-07-11 09:52 | Bamboo_wan [未注册用户]
对了大哥,你做的设计模式的pdf版本在博区哪个地方,我想下来学习
  回复  引用    
#14楼 2008-07-11 09:57 | 室温 [未注册用户]
楼主真是好样子,居然笔耕不断,佩服,我想问一下,你怎么这么有时间呀,我们上班族的时间被占的满满的,难道你全部是晚上?
  回复  引用  查看    
#15楼 [楼主]2008-07-11 09:59 | TerryLee      
@Bamboo_wan
你到这个地址去下载:
http://www.cnblogs.com/Terrylee/archive/2006/05/23/406688.html
  回复  引用  查看    
#16楼 [楼主]2008-07-11 10:00 | TerryLee      
@室温
呵呵,谢谢支持。

现在只能是利用晚上的时间了,好在我现在有个项目在使用Silverlight,所以平时工作中也积累了一些心得和技巧等:)
  回复  引用    
#17楼 2008-07-11 11:12 | 汉字输入 [未注册用户]
请问楼主有没有遇到过除微软拼音输入法之外的其他中文输入法在SL中输入汉字都会重复显示的问题?
  回复  引用  查看    
#18楼 2008-07-11 11:56 | hxm      
#12: Loading Dynamic XAPs and Assemblies

(21 minutes, 12 seconds)

对吧

对了 今天早上又出6个新的SL2 VIDEO了 有的忙了

WEBCAST这种教程方式真的很不错。。。。
之后可以写文章解析一下。
  回复  引用    
#19楼 2008-07-11 11:58 | bugonline [未注册用户]
@汉字输入
我遇到过,我用sohu输入法,统统给我显示了2遍。
  回复  引用  查看    
#20楼 [楼主]2008-07-11 12:26 | TerryLee      
@汉字输入
呵呵,是有这个问题

刚开始还以为是我电脑问题,后来换了几台机器测试,确实有这个问题:)
  回复  引用  查看    
#21楼 [楼主]2008-07-11 12:26 | TerryLee      
@hxm
今天刚看到,之前很少有时间看WebCast。
  回复  引用  查看    
#22楼 [楼主]2008-07-11 12:27 | TerryLee      
@bugonline
嗯,我用搜狗输入法,也是有这个问题!
  回复  引用  查看    
#23楼 2008-07-11 14:07 | airwolf2026      
微软拼音好恶心啊...以前写的脚本既然不支持微软拼音...囧rz
  回复  引用  查看    
#24楼 2008-07-11 14:08 | airwolf2026      
webcast英文讲解的话,还是听不来啊.用看的倒是还行...
  回复  引用  查看    
#25楼 2008-07-11 15:23 | 装配脑袋      
访问本地的另一个Xap或dll行吗?似乎这些方法都限制xap和动态加载的dll必须来自于web……
  回复  引用  查看    
#26楼 [楼主]2008-07-11 15:27 | TerryLee      
@airwolf2026
平时从来不用微软拼音,偏偏Silverlight 2 Beta 2中只支持微软拼音:(
  回复  引用  查看    
#27楼 [楼主]2008-07-11 15:27 | TerryLee      
@装配脑袋
应该是没有问题的,可以使用OpenFileDialog来打开一个本地的xap文件或者dll程序集:)
  回复  引用  查看    
#28楼 2008-07-11 15:32 | 装配脑袋      
OpenFileDialog……有时候我真的希望WebClient能够支持本地启动的SL程序访问本地文件。。
  回复  引用  查看    
#29楼 2008-07-11 15:57 | 无常      
Assembly assembly = LoadAssemblyFromXap(e.Result, "ExternalProject.dll");

-----
如果这个程序集中的控件还用到很多其它DLL中的类呢
  回复  引用  查看    
#30楼 [楼主]2008-07-11 16:07 | TerryLee      
@装配脑袋
o(∩_∩)o...
  回复  引用  查看    
#31楼 [楼主]2008-07-11 16:09 | TerryLee      
@无常
这似乎没有什么关系,如果还用到其它的程序集,都会打包在xap文件,也会在AppManifest.xaml中列出清单,也就是说,你肯定可以在xap中找到所有需要的程序集,只要重新组织一下上面的代码结构就行了。
  回复  引用  查看    
#32楼 2008-07-11 17:55 | RogerTong      
TerryLee,一直在看你的文章,最后忍不住取了同你相雷同的名字来这里开博,不会告我侵权吧,哈哈,加个链接如何?
  回复  引用  查看    
#33楼 [楼主]2008-07-11 18:18 | TerryLee      
@RogerTong
当然没有问题,Tech Space这个词不是我的专利,呵呵

我已经加好链接了,在我的个人站点http://www.dotneteye.cn上也加了你的链接:)
  回复  引用    
#34楼 2008-08-19 22:08 | silverlight学习中 [未注册用户]
示例代码下载无法下载啊!还有其他可以下载的链接么?
  回复  引用  查看    
#35楼 [楼主]2008-08-20 10:09 | TerryLee      
@silverlight学习中
好像是最近SkyDriven关闭了,也许过段时间会开。。。
  回复  引用    
#36楼 2008-08-26 00:08 | samu zhang [未注册用户]
我使用美国的ip就可以下载,用中国的就不行的
  回复  引用  查看    
#37楼 [楼主]2008-08-26 09:50 | TerryLee      
@samu zhang
那看来是对中国地区关闭了,好多东西还在上面呢。。。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-07-10 22:29 编辑过


相关链接: