继WPF,Silverlight和Silverlight for Windows Phone之后,微软又推出了另一个以XAML为基础的平台WinRT,暂且这么称呼吧。WinRT作为Win8 Metro程序的主要开发平台应该会在很长时间被微软支持,不像短命的Silverlight系。
WinRT较之Silverlight到WPF的变化更大。其底层变为了一个以COM为基础的平台。使用C#等.NET语言编写的程序会被编译为可以在WinRT上运行的本地代码。
这篇文章不详细讨论WinRT的底层平台,也不去研究WinRT里面新增的专用于非托管环境的类型,而是侧重于看看XAML方面的变化,从而为由WPF和Silverlight到WinRT的迁移提供帮助。
另外针对一些应用程序生命周期,导航的变化也不是本文的重点,目前来看这些还是与所运行系统相关的,不像XAML这么具有普遍性。许多事件也在WinRT环境下被精简了,因为WinRT主要用于触屏环境,可能微软认为支持基础的的触摸相关事件就够了。
关于一份详细的变化列表,可以见MSDN中的这篇文章。本文列举中其中我遇到的或是比较突出(像是Stackoverflow上被问及很多)的一些变化。
图形图像样式相关
WinRT移除了WPF中可用的位图效果,这些效果在移动平台可能比较慢。就连OpacityMask也不被支持。
VideoBrush在WinRT中也无法使用,但最值得吐槽的是RadialGradientBrush莫名其妙的不被支持了,这个在Stackoverflow也有很多吐槽,难道是微软开始支持扁平化效果就认为RadialGradientBrush和扁平化不对路同时也影响性能就给干掉了?
另外WinRT中处理图像有自己的一套名为WIC的API,这套API和.NET中的完全不一样。如果要在WinRT中处理图像的这部分代码迁移的工作量将是非常大的。这里就不细说了。
顺便提一句,在WinRT中文件访问API也是全新的,和.NET中那套文件访问也是截然不同,顺应异步话趋势,所有这些API都提供异步调用方式,有些甚至只能以异步方式来访问。
控件
WinRT中定义了很多默认样式和Windows Metro风格一致的控件,以前的经典控件都有了新的版本,也增加了一些新的控件如SemanticZoom等。如果使用过WPF,WinRT中这些控件也很好上手。这个就不再细说了,重点关注下自定义控件方面。WinRT同样是支持UserControl和TemplatedControl两种自定义控件的方式。UserControl变化不大,TemplatedControl有些小的细节进行了改变需要注意下:
变化1:
在自定义模板控件时,WPF控件中指定样式的方式是(在静态构造函数中):
DefaultStyleKeyProperty.OverrideMetadata(typeof(CircleMenuControl), new FrameworkPropertyMetadata(typeof(CircleMenuControl)));
而WinRT的方式相对简单(在构造函数中):
DefaultStyleKey = typeof(Chart);
变化2:
WPF模板空间中OnApplyTemplate的访问等级是public,而WinRT中是protected,在重写函数时应该注意。
变化3:
在Generic.xaml中指定外部样式文件时,WPF中引用的方式是:
<ResourceDictionary Source="/Zq.Control;component/Flow/FlowControl.xaml"></ResourceDictionary>
而WinRT中有所不同:
<ResourceDictionary Source="ms-appx:///Win81Demo.Controls/CircleMenuControl/CircleMenu.xaml" />
变化4:
WinRT路由事件不支持自定义,对于一些有嵌套关系的自定义控件,把子控件的事件向上发布没有那么容易了。真不知道WinRT不支持自定义控件的理由是啥。
变化5:
对于自定义一个从ItemsControl继承的控件。在WPF中由于ItemsPresenter不是密封类,这样可以自定义一些ItemsPresenter的子类,在自定义ItemsPresenter中添加一些依赖属性,供我们的自定义面板绑定这样,一些自定义面板可以绑定到这些依赖属性,从而提供一种控制自定Panel的方式。而WinRT中ItemsPresenter变成了密封类,没法按WPF中那种方式去使用。所以从ItemsControl继承也就失去了很多优势。
动画
WPF支持的Transform类型的BeginAnimation方法,在WinRT的Transform中不被支持,WinRT的Animation类也没有这么多构造函数的重载。
如在WPF中可以用transform.BeginAnimation()方法直接开始一个动画在WinRT中就不行。在WinRT中控制动画只能老老实实的用StoryBoard相关方法,控制的对象可以是Transform的各种属性值。
另外在WinRT中一个单独元素只能运行一个Storyboard。如果需要两个独立的动画效果,一种方式是声明2个元素,分别关联两个Storyboard在其中引用不同的动画效果。