星辰.Net技术社区论坛

首页 » .NET » Silverlight » 在Silverlight中如何访问外部xap文件中UserControl
admin - 2008-7-11 9:31:00
概述5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
众所周知,在Silverlight 2开始每个项目编译后都会打包成为一个xap文件,如果我们要访问当前xap文件中的UserControl比较容易,那我们如何访问一个外部xap文件中的内容呢?甚至于如何访问一个互联网上的xap文件呢?5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
本文将简单介绍一下在Silverlight中如何访问外部xap文件。5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
需求5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
现在我们先来看一下需求,大致是这样子的,在服务端我们有两个xap文件,其中MainProject.xap文件将会在MainProjectTestPage.aspx中引用,而ExternalProject.xap文件中的UserControl将会在MainProject.xap文件中访问,并进行显示,如下图所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
现在我们来建立相关的项目,最终完成的项目结构如下图所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
  5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
这样在编译后,将会在ClientBin文件夹下产生两个.xap文件,现在我们将在MainProject.xap文件中访问ExternalProject.xap中的UserControl。5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
分析5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
在实现这个过程中,我们将会遇到两个问题:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
1.因为没有任何页面引用ExternalProject.xap文件,所以它不会下载到客户端,这一点我们可以通过编码的方式来下载它。5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
2.访问ExternalProject.xap中的UserControl,我们需要找到对应的程序集,以便使用反射,我们知道在xap文件是一个标准的zip文件,它会包含相关的程序集(接下来我会写一篇文章专门解释xap文件),如下图所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
现在解决了xap文件的下载已经程序集的访问问题,我们可以着手来实现了。5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
实现 实现的过程也是相当简单,首先我们使用WebClient去下载xap文件,相信大家都知道该怎么做了,如下代码所示5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
void myButton_Click(object sender, RoutedEventArgs e)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
{5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    Uri address = new Uri("http://localhost:4161/ClientBin/ExternalProject.xap");5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    WebClient webClient = new WebClient();5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    webClient.OpenReadAsync(address);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
}5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
{5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    // 得到下载结果5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
}
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
这一步比较简单,接下来我们将根据下载的结果,得到相应的程序集。我们知道在xap文件中的AppManifest.xaml文件相当于一个清单,列出了当前xap文件用到的程序集(下篇文章将会介绍),它的内容如下所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            EntryPointAssembly="ExternalProject" 5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            EntryPointType="ExternalProject.App" 5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            RuntimeVersion="2.0.30523.6">5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
  <Deployment.Parts>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    <AssemblyPart x:Name="ExternalProject" Source="ExternalProject.dll" />5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
  </Deployment.Parts>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
</Deployment>
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
注意,在Deployment.Parts节点下包含了当前应用程序中所有的程序集。首先要根据下载的结果获取AppManifest.xaml文件中的内容,如下代码所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
Stream stream = Application.GetResourceStream(5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        new StreamResourceInfo(packageStream, null),5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        new Uri("AppManifest.xaml", UriKind.Relative)).Stream;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
String appManifestString = new StreamReader(stream).ReadToEnd();
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
有了AppManifest.xaml中内容,就可以根据它来构造一个Deployment对象,Deployment对象提供了当前应用程序的Part和本地化信息清单,它的定义如下所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
注意它定义了一个很重要的属性Parts,通过该属性我们就可以访问所有Deployment中的程序集。好了,现在我们看如何通过AppManifest.xaml中的内容构造Deployment对象,以及遍历其中的程序集,如下代码所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
Deployment deployment = (Deployment)XamlReader.Load(appManifestString);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
Assembly assembly = null;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
foreach (AssemblyPart assemblyPart in deployment.Parts)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
{5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    if (assemblyPart.Source == assemblyName)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    {5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        String source = assemblyPart.Source;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        StreamResourceInfo streamInfo = Application.GetResourceStream(5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            new StreamResourceInfo(packageStream,5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            "application/binary"),5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            new Uri(source,UriKind.Relative));5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        assembly = assemblyPart.Load(streamInfo.Stream);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        break;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    }5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
}5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
return assembly;
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
注意,在遍历时如果我们找到程序集名等于我们想要访问的程序集,则直接返回该程序集。最终完整的LoadAssemblyFromXap方法代码如下:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
Assembly LoadAssemblyFromXap(Stream packageStream,String assemblyName)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
{5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    Stream stream = Application.GetResourceStream(5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            new StreamResourceInfo(packageStream, null),5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            new Uri("AppManifest.xaml", UriKind.Relative)).Stream;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    String appManifestString = new StreamReader(stream).ReadToEnd();5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    Deployment deployment = (Deployment)XamlReader.Load(appManifestString);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    Assembly assembly = null;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    foreach (AssemblyPart assemblyPart in deployment.Parts)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    {5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        if (assemblyPart.Source == assemblyName)5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        {5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            String source = assemblyPart.Source;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            StreamResourceInfo streamInfo = Application.GetResourceStream(5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
                new StreamResourceInfo(packageStream,5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
                "application/binary"),5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
                new Uri(source,UriKind.Relative));5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            assembly = assemblyPart.Load(streamInfo.Stream);5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
            break;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        }5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    }5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    return assembly;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
}
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
得到程序集后,再使用反射创建相关的实例,并在页面上加载,如下代码所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
Assembly assembly = LoadAssemblyFromXap(e.Result, "ExternalProject.dll");5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
UIElement element = assembly.CreateInstance("ExternalProject.SubPage") as UIElement;5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
this.holder.Children.Add(element);
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
运行后效果如下图所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
跨域访问在上面的示例中,不涉及到跨域(我会专门写一篇文章介绍)调用的问题,如果大家想访问的xap文件与当前xap文件不在同一站点中,需要添加跨域访问文件,如下代码所示:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
clientaccesspolicy.xml:5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
<?xml version="1.0" encoding="utf-8"?>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
<access-policy>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
  <cross-domain-access>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    <policy>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
      <allow-from http-request-headers="*" />5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
      <domain uri="*"/>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
      </allow-from>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
      <grant-to>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
        <resource path="/" include-subpaths="true"/>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
      </grant-to>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
    </policy>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
  </cross-domain-access>5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
</access-policy>
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
5ù^ò'®«www.netcsharp.cnÀê–ß8^•RÂ
1
查看完整版本: 在Silverlight中如何访问外部xap文件中UserControl