2012年7月28日星期六

从WPF到Silverlight到WinRT:导航的变化

从WPF到Silverlight到WinRT:导航的变化

导航在后期微软界面程序设计的地位越来越高,最初在WPF中,导航仅仅是一个可用组建,可以在普通程序中使用,也可以在浏览器中使用,也就是所谓的WPF Browser App,文件类型是XBAP。但是这都仅仅是一个可用可不用的组件。而在Silverlight和WinRT中,“导航”已经代替传统意义上的“窗口”,成为每一个应用程序必须适应的模式。

 

在WPF(WPF4)中:导航的核心是NavigationService类型,Frame,NavigationWindow和Page类型都有NavigationService属性,同时Frame类型还有一些方法比如Navigate就是直接调用其背后NavigationService的相应方法。

Frame继承自ContentControl,Page继承自FrameworkElement。

 

Navigate方法可以传入Uri和Object参数,同时支持第二个Object代表额外数据。然后在Frame.Navigated事件中,通过NavigationEventArgs的ExtraData属性来获取额外的数据。但是WPF中的导航数据传递对于开发者来说很头疼。这个在Silverlight中有所改进。详细信息可以参考:

WPF和Silverlight:导航Page中数据的传递

 

Page类型没有提供任何事件或者可改写方法来报告自己的状态,在导航传值中非常不方便。一切事件决策在Frame类型中。

 

最后Page的缓存可以通过KeepAlive和FrameworkPropertyMetadataOptions.Journal设置。

 

 

接着在Silverlight(Silverlight 5)中,首先导航相关类型到一个专属程序集:System.Windows.Controls.Navigation.dll,当然Page和Frame所在命名空间还是System.Windows.Controls,没有了NavigationWindow。。。

类型的集成树也有所改变,Frame还是ContentControl但是Page继承自UserControl。Frame和Page都仍然有NavigationService,但是Frame的NavigationService成了internal,但是他有public的包装方法,比如Navigate,Refresh等。

 

Silverlight中Page加入了可改写方法来弥补WPF在此的空白,用户可以通过OnNavigatedFrom和OnNavigatedTo以及OnFragmentNavigation方法来在适当事件后进行适当代码操作。Silverlight中Frame的Navigate只有Uri参数,当然也可以传入Uri形式的额外参数(类似Query String),具体传递数据可以参考:WPF和Silverlight:导航Page中数据的传递(貌似我上面已经写过)。

 

最后Silverlight中Page的缓存也和WPF大大不一样,没有KeepAlive和FrameworkPropertyMetadataOptions,用户可以使用NavigationCacheMode和CacheSize。具体可以参考:

WPF和Silverlight:Frame中Page的缓存设置

 

在WinRT中,没有了NavigationService。或许内部有类似的东西,但是我们无法看到既然WinRT是C++编的。Page仍然是UserControl,成员如下:

image

 

NavigationCacheMode和3个方法在Silverlight中都有的。同时Page还加入了一些新的元素。比如WinRT中特有的AppBar。最后比较有意思的是WinRT中的Page同时引用Frame对象,这个可以说是NavigationService的代替吧,因为如果Page连Frame都不引用,那么Page本身就不具备任何主动导航功能了!

 

再来看看Frame类型,类似Silverlight中的Frame。不过最大的改变就是Navigate方法,是以Type来Navigate的,而不是Silverlight中的Uri,更不是WPF曾有的Object对象。是Type。因此Frame的数据属性也被改成Type相关的,比如CurrentSourcePageType。

 

Navigate方法同时可以传入Object参数,那么可以这样:

var rootFrame = new Frame();

if (!rootFrame.Navigate(typeof(MainPage), "Mgen"))

{

    throw new Exception("Failed to create initial page");

}

 

在Page中通过改写OnNavigatedTo,从NavigationEventArgs中获取额外数据,如下代码:

protected override void OnNavigatedTo(NavigationEventArgs e)

{

    System.Diagnostics.Debug.WriteLine(e.Parameter);

}

 

非常好,WinRT中导航传值非常简单。可以看到WinRT既有WPF的传递Object参数功能,又有Silverlight中Page的方法,也算得上是微软在XAML探索路上更成熟的一个里程碑吧。


TAG: