silverlight 4,动态加载xap模块

时间:2010-09-09 04:08:26

标签: silverlight assembly-resolution xap

我知道可以使用Prism或MEF框架动态加载xap模块。但是,我不想使用这些框架;而是手动加载我的xap文件。所以,我创建了以下课程(改编自互联网):

public class XapLoader
{
    public event XapLoadedEventHandler Completed;

    private string _xapName;

    public XapLoader(string xapName)
    {
        if (string.IsNullOrWhiteSpace(xapName))
            throw new ArgumentException("Invalid module name!");
        else
            _xapName = xapName;
    }

    public void Begin()
    {
        Uri uri = new Uri(_xapName, UriKind.Relative);
        if (uri != null)
        {
            WebClient wc = new WebClient();
            wc.OpenReadCompleted += onXapLoadingResponse;
            wc.OpenReadAsync(uri);
        }
    }

    private void onXapLoadingResponse(object sender, OpenReadCompletedEventArgs e)
    {
        if ((e.Error == null) && (e.Cancelled == false))
            initXap(e.Result);

        if (Completed != null)
        {
            XapLoadedEventArgs args = new XapLoadedEventArgs();
            args.Error = e.Error;
            args.Cancelled = e.Cancelled;
            Completed(this, args);
        }
    }

    private void initXap(Stream stream)
    {
        string appManifest = new StreamReader(Application.GetResourceStream(
        new StreamResourceInfo(stream, null), new Uri("AppManifest.xaml",
                                       UriKind.Relative)).Stream).ReadToEnd();

        XElement deploy = XDocument.Parse(appManifest).Root;

        List<XElement> parts = (from assemblyParts in deploy.Elements().Elements()
                                select assemblyParts).ToList();

        foreach (XElement xe in parts)
        {
            string source = xe.Attribute("Source").Value;
            AssemblyPart asmPart = new AssemblyPart();
            StreamResourceInfo streamInfo = Application.GetResourceStream(
                 new StreamResourceInfo(stream, "application/binary"), 
                 new Uri(source, UriKind.Relative));
            asmPart.Load(streamInfo.Stream);
        }
    }
}

public delegate void XapLoadedEventHandler(object sender, XapLoadedEventArgs e);

public class XapLoadedEventArgs : EventArgs
{
    public Exception Error { get; set; }

    public bool Cancelled { get; set; }
}

以上代码工作正常;我可以通过以下方式加载任何xap:

XapLoader xapLoader = new XapLoader("Sales.xap");
xapLoader.Completed += new XapLoadedEventHandler(xapLoader_Completed);
xapLoader.Begin();

现在,我在Sales.xap项目中有一个名为InvoiceView的UserControl,所以我想实例化该类。在当前项目(Main.xap)中,我添加了对Sales.xap项目的引用,但是,因为我手动加载它,所以设置“Copy Local = False”。但是在执行时,以下代码抛出TypeLoadException:

Sales.InvoiceView view = new Sales.InvoiceView();
似乎代码找不到InvoiceView类。但我检查了XapLoader的initXap()方法是否成功执行。那么为什么代码找不到InvoiceView类呢?有人可以帮我解决这个问题吗?

4 个答案:

答案 0 :(得分:1)

好的,我找到了原因。上面的代码有效。创建一个新的Silverlight项目(Sales.xap)后,我碰巧编译了我的解决方案一次。然后我删除了Sales.xap中的App类,并将默认的MainPage类重命名为SalesView。但是,无论我编译我的解决方案多少次,Visual Studio的开发Web服务器都加载了Sales.xap的第一个版本(从哪里开始?),所以我的代码找不到SalesView。在我的主机Asp.Net项目中,我将开发服务器的端口设置为不同的端口号,问题就消失了。所以问题出在Visual Studio的开发服务器上。显然它将编译的xap文件保存在某个临时文件夹中,并且在源代码更改时并不总是更新这些xap文件。

答案 1 :(得分:1)

这是基于提问者在下面的自我答案,而不是问题。

如果删除项目/模块,输出DLL / XAP文件会挂起。如果单击“显示所有文件”按钮,您将在 clientbin bin obj 文件夹中看到一些这些遗留输出文件。相关项目。

alt text

您可以从项目中单独删除它们,或者,如果有疑问,搜索所有BIN和OBJ(例如使用桌面浏览器)并删除所有这些文件夹。将在需要时重新创建BIN / CLIENTBIN / OBJ文件夹(这是Visual Studio中“clean”选项应该完成的工作!)

希望这有帮助。

答案 2 :(得分:0)

在执行新编译的Silverlight时,我做了什么来避免这些问题,浏览器缓存很清楚,chrome甚至还有一个清晰的Silverlight缓存;)

答案 3 :(得分:0)

这种XAP Cache现象通常是由visual studio嵌入式Web服务器(ASP.NET Development Server)引起的。 只需停止此服务器的出现,将清除缓存。 重新开始您的项目,并调用最新版本的xap。