SilverLight系列——动态装载XAP包

      其实关于动态装载XAP包,网上已有不少资料,且都附有代码,我当初也是参考网上找到的代码改的,基本原理就是通过WebClient请求XAP文件流,然后分析流,加载程序集,最后通过反射创建实例。细节方面,直接看代码就可以很清楚了:

   /// <summary>
    /// XAP包加载器
   /// </summary>
    public class XapLoader
    {
        /// <summary>
        /// XAP包路径
      /// </summary>
        private string _xapUri;

        public XapLoader(string xapUri)
        {
            _xapUri = xapUri;
        }

        /// <summary>
        /// 加载元素完毕时触发此事件
      /// </summary>
        public event EventHandler<XapLoadEventArgs> LoadCompleted;

        /// <summary>
        /// 从XAP包中加载指定的Xaml文件并实例化为FrameworkElement
        /// </summary>
        /// <param name="xamlFileName">Xaml文件路径</param>
        public void LoadXaml(string xamlFileName)
        {
            Uri uri = new Uri(_xapUri, UriKind.Relative);

            WebClient client = new WebClient();
            client.OpenReadCompleted += (sender, e) =>
            {

                StreamResourceInfo resource = Application.GetResourceStream(
                    new StreamResourceInfo(e.Result, null),
                    new Uri(xamlFileName, UriKind.Relative));

                string resourceMainfest = new StreamReader(resource.Stream).ReadToEnd();
                FrameworkElement element = null;
                string errorMessage = null;

                try
                {
                    element = XamlReader.Load(resourceMainfest) as FrameworkElement;
                }
                catch (Exception ex)
                {
                    errorMessage = ex.Message;
                }

                if (LoadCompleted != null)
                    LoadCompleted(this, new XapLoadEventArgs(element, errorMessage));
            };

            client.OpenReadAsync(uri);
        }

        /// <summary>
        /// 从XAP包中的指定程序集中加载指定的类型
      /// </summary>
        /// <param name="assmblyName">程序集名称(含后缀)</param>
        /// <param name="typeName">加载类型的完全限定名</param>
        public void LoadControl(string assmblyName, string typeName)
        {
            Uri uri = new Uri(_xapUri, UriKind.Relative);

            WebClient client = new WebClient();
            client.OpenReadCompleted += (sender, e) => {

                if (e.Error != null)
                {
                    if (LoadCompleted != null)
                        LoadCompleted(this, new XapLoadEventArgs(null, e.Error.Message));
                    return;
                }

                StreamResourceInfo resource = Application.GetResourceStream(
                    new StreamResourceInfo(e.Result, null),
                    new Uri("AppManifest.xaml", UriKind.Relative));

                string resourceMainfest = new StreamReader(resource.Stream).ReadToEnd();
                var asmPartEls = XDocument.Parse(resourceMainfest).Root.Elements().Elements();

                Assembly assembly = null;
                foreach (XElement asmPartEl in asmPartEls)
                {
                    string source = asmPartEl.Attribute("Source").Value;

                    if (string.Compare(source,assmblyName, StringComparison.InvariantCultureIgnoreCase)==0)
                    {
                        StreamResourceInfo streamInfo = Application.GetResourceStream(
                            new StreamResourceInfo(e.Result, "application/binary"),
                            new Uri(source, UriKind.Relative));
                        AssemblyPart assemblyPart = new AssemblyPart();
                        assembly = (new AssemblyPart()).Load(streamInfo.Stream);
                    }
                }

                if (assembly == null)
                {
                    if (LoadCompleted != null)
                        LoadCompleted(this, new XapLoadEventArgs(null, "未能找到指定程序集!"));
                }
                else
                {
                    FrameworkElement element = null;
                    string errorMessage = null;

                    try
                    {
                        Type type = assembly.GetType(typeName);
                        element = Activator.CreateInstance(type) as FrameworkElement;
                    }
                    catch (Exception ex)
                    {
                        errorMessage = ex.Message;
                    }

                    if (LoadCompleted != null)
                        LoadCompleted(this, new XapLoadEventArgs(element, errorMessage));
                }
            };

            client.OpenReadAsync(uri);
        }
    }
    /// <summary>
    /// 加载XAP包事件参数
    /// </summary>
    public class XapLoadEventArgs : EventArgs
    {
        private XapLoadEventArgs() { }

        public XapLoadEventArgs(FrameworkElement element, string error)
        {
            _element = element;
            _error = error;
        }

        private string _error;
        /// <summary>
        /// 获取加载时包含的错误信息
        /// </summary>
        public string Error
        {
            get { return _error; }
        }

        private FrameworkElement _element;
        /// <summary>
        /// 获取加载的UI元素
        /// </summary>
        public FrameworkElement Element
        {
            get { return _element; }
        }
    }

      使用方法:

    XapLoader loader = new XapLoader(xapfile);
    loader.LoadCompleted += new EventHandler<XapLoadEventArgs>(loader_LoadCompleted);
    loader.LoadControl(assembly, pageclass);
    然后在loader_LoadCompleted里通过事件参数的Element属性获取加载的UI实例即可。
 

最后有很重要的一点要提醒:

比如有SL主程序APP,其中引用了程序集A.DLL,动态加载的XAP包中也包含了程序集A.DLL,但是版本与主程序中引用的不一致,那么
从XAP包中实例化的对象也将尝试使用主程序APP中所加载的A.DLL,而非XAP包中的A.DLL。所以,这种情况下如果提示“×××方法不存在”,就不要再纳闷了。
posted @ 2011-08-15 22:50  细雨黄昏  阅读(1155)  评论(1编辑  收藏  举报