Silverlight 的导航框架与动态加载
1. Silverlight 3 的导航框架简介
Silverlight 提供了内置的导航框架,可以比较轻松的在 Silverlight Page 之间进行切换,并且可以和浏览器的前进、后退按钮集成,下面的代码可以简单的说明其用法:
这段代码很简单,通过设置 HyperLinkButton 的 NavigationUri 和 TargetName 两个属性,可以让指定的 Frame 去加载指定的 Silverlight Page 。
2. 常见的动态加载解决方案
当 Silverlight 项目比较大的时候, 很自然的会想到将 Silverlight 项目拆分成多个 xap 文件,进行按需加载,这个实现起来也不难。通常的做法是使用 WebClient 或者 HttpWebRequest ,向服务端请求所需的 xap 文件,然后通过 xap 压缩包内的 AppManifest.xaml 文件,获取到 xap 文件内部打包的 dll 文件信息,在客户端通过反射进行加载。
3. 导航框架与动态加载相结合时遇到的问题,原因与解决方法
如果将这两者结合起来,利用 Sliverlight 内置的导航框架来加载动态加载的 xap 文件内部的 Silverlight Page ,对应用程序的开发和用户体验都是有很大帮助的:对开发方面来说,不用反射加载,而是使用 Silverlight 内置的导航框架,可以节省很多代码;对用户体验方面,按需加载能减少初始加载文件的大小,减少等待时间,使用导航框架可以和浏览器的前进、后退按钮紧密集成,用户体验更佳。
但是,在 Silverlight 3 目前的版本中, Frame 控件似乎不能直接加载动态加载的 Silverlight Page , 不管是通过设置 HyperLinkButton 的 NavigateUri 属性,还是通过调用 Frame.Navigate(Uri source) 方法,都会出现相同的异常, 看下面代码:
var xap = "http://localhost:2704/AppSL.Web/ClientBin/TestSLApp.xap"; // LoadPackage 是加载 xap 的扩展方法 Deployment.Current.LoadPackage(xap, () => { var uri = new Uri("/TestSLApp;component/MainPage.xaml", UriKind.Relative); this.WidgetFrame.Navigate(uri); });
当执行至 WidgetFrame.Navigate(uri) 时,会出现下面的异常:
是什么原因导致这个异常呢? 通过 Reflector 察看 PageResourceContentLoader ,发现加载 x:Class 的是这个 GetTypeFromAnyLoadedAssembly 方法:
这个方法只是遍历 Deployment.Current.Part 去寻找所需要的类型,并没有去遍历动态加载的文件, 当然,这里也不可能去遍历。
看到这里,终于找到异常出现的原因了,由于这个方法是私有并且是静态的,无法进行重写,只能通过其它途径来解决。我想到的解决方法是,新建一个 Silverlight Page, 然后删除对应的代码文件,删除 xaml 视图的 x:Code 信息,如下图所示:
最后的解决方案就是, 要做一个引导的文件,这个文件必须是一个独立的 xaml 文件,没有代码文件,没有 x:Class 信息,这样就不会被编译成新的类型,自然可以被 Silverlight 的导航框架加载了。
最后说一句,不知道 Silverlight 以后的版本会不会考虑动态加载的问题呢? 据我所知, Flex 已经内置了模块动态加载的机制了。
张志敏所有文章遵循创作共用版权协议,要求署名、非商业 、保持一致。在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处。
本博客已经迁移到 GitHub , 围观地址: https://beginor.github.io/