XAML中有两个类型值得细细品味,一个是Page,另一个是Panel。这两个类型代表了XAML UI对象的组织方式。

首先来看看Page和Panel是如何定义的

  • DependencyObject
    • UIElement
      • FrameworkElement
        • TextBlock
        • Image
        • Panel
          • Grid
        • Control
          • UserControl
            • Page

首先这两个类型都是从FrameworkElement中派生出来的。Panel是FrameworkElement的直接派生类,而Page隔着两层,分别是ControlUserControl。之所以这样安排,是因为Page常常含有自定义的逻辑,所以是一种Control。Control有若干种,出了UserControl之外,还有ContentControl和ItemsControl。UserControl常常用于自定义控件。

Page是XAML UI的顶层组织元素。一个XAML UI包含有若干个窗口,每个窗口里面是一个Frame可以包括若干个Page,然后可以在这些Page中切换。Page的Content属性。Page的ContentProperty所映射的是自身的Content属性,其类型是UIElement,也就是说只能嵌套一个子UIElement,而不能包含多个子UIElement 。

如果Page需要包含多个UIElement,就是需要Panel帮忙。Panel的ContentProperty是Children属性,其类型是一个UIElementCollection。一个UIElementCollection 可以包含多个UIElement,于是就可以组织成一个UIElement的层级。

由此可以知道,窗口包含一个帧框(Frame),帧框可以在一至多个页面(Page)切换,每个页面可以包含一个面板(Panel),而面板可以包含其他元素或者自身,于是乎层层嵌套,最终变为一颗树状结构。那问题来了,这棵树上的元素是需要在屏幕上显示的,那应该如何布局呢?

布局这个过程其实是两个方向齐头并进的,上面的帧框知道自己在屏幕上的大小,但是不知道子元素的大小。此外,每个子元素知道自身的大小(比如一个文本块知道自身的大小),但是不知道自己可以在多大的区域内显示,需不需要对内容进行裁剪。所以实际布局的时候,只有从顶层和底层两个方向同时进行,才能知晓布局的具体结构。而这一般采用的是深度遍历优先的做法。

对于事件处理的话,Panel和Page也不一样。Panel的事件处理是从UIElement继承下来的,而虽然UIElement也是Page的前续基类,但是中间的Control却增加了许多虚拟的事件处理机能。比如对于点击事件,在UIElement中定义的是Tapped,但是Control却增加了一个虚拟的OnTapped,区别是OnTapped可以被x:Class指定的幕后类型中重新定义。

(完)