Attention!以下各主题为WPF中的重要新特性、新概念,掌握了这些内容之后再去阅读其它书籍将会事半功倍。
逻辑树和视觉树(Logical and Visual Tree)
在WPF中,用户界面以对象树的形式构建,称作“逻辑树”。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="关于WPF揭秘" SizeToContent="WidthAndHeight"
Background="OrangeRed">
<StackPanel>
<Label FontWeight="Bold" FontSize="20" Foreground="White">
WPF揭秘(版本3.0)
</Label>
<Label>(C)2006 SAMS 出版公司</Label>
<Label>已安装的章节:</Label>
<ListBox>
<ListBoxItem>第一章</ListBoxItem>
<ListBoxItem>第二章</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button MinWidth="75" Margin="10">Help</Button>
<Button MinWidth="75" Margin="10">OK</Button>
</StackPanel>
<StatusBar>您已经成功注册了本产品。</StatusBar>
</StackPanel>
</Window>
逻辑树并不只存在于由XAML创建的WPF用户界面中,上例完全可由程序代码写成,同样存在逻辑树。逻辑树是一个很直接的概念,既然这样我们为什么还要关心它呢?这是因为,几乎WPF的每个方面(如属性、事件、资源等等)都有依赖逻辑树的行为。例如,属性值有时候会自动沿着逻辑树向下传导,并且可以沿着逻辑树向上或向下触发事件。
上例对应的逻辑树为:
图1
视觉树的概念与逻辑树相似,它是对逻辑树的基本扩展。视觉树中的节点穿透了它们的核心视觉组件(看图2,意思是说视觉树的节点夹在逻辑树的节点之间,逻辑树的节点可看作核心视觉组件),并且暴露了视觉实现的细节,而不是将树上的每一个元素当作黑盒子。比如说,尽管ListBox逻辑上是一个单独的控件,但是它的默认视觉实现(确实是默认的,因为这个视觉实现方式可以修改!)则是由许多WPF基本元素构成:一个边框(Border)和两个滚动条(ScrollBar)等。
并不是所有的逻辑树节点都会出现在视觉树中,只有那些从System.Windows.Media.Visual或从System.Windows.Media.Visual3D派生的元素才会。其他元素和简单的字符串内容都不会出现在视觉树中,因为它们不包含继承的呈现(rendering)行为。
下图表示上例在Vista中Aero主题下的默认视觉树,其中边框较粗的是在逻辑树上也有的节点。
图2
这张图暴露一些当前不可见的UI内部组件,如ListBox的两个ScrollBar和Label的Border。除此之外,它还揭示了除按钮使用了ButtonChrome而不是Border之外,Button、Label和ListBoxItem都由共同的元素组成(Border和ContentPresenter)。此外,由于不同的默认属性值使得这些控件拥有不同的视觉效果,如Button的Margin属性默认值是10,而Label的Margin属性默认值则为0。
从WPF元素的深度组合可以看出来,视觉树可以是难以想象得复杂。不过尽管视觉树是WPF基础结构的本质部分,却并不需要担心,除非我们需要彻底改变控件的风格,或者做一些低级别的绘画操作。另外需要注意到,为Button编写依赖于特定视觉树的代码将会损害WPF的核心原则之一——外观和逻辑的分离。