zoukankan      html  css  js  c++  java
  • WPF Unleashed Chapter 3:Important New Concepts in WPF Logical and Visual Trees 翻译

      本书的第一部分已经介绍完了,在开始接触wpf真正有意思的部分之前,我将介绍一些.NET程序员不太熟悉的概念。这些概念是WPF所特有的,是学习WPF的拦路虎,只有掌握之后,您才能更好地掌握本书后面介绍的知识。 

         其中的一些概念是WPF特有的(例如逻辑树和视觉树);还有一些是在原有个概念的一些扩充(例如属性(property)和事件)。学习完这些概念后,我们提供了一个应用这些概念的例子:一个"About dialog"
       
         逻辑树和视觉树 

         XAML天然的层次性使得它非常适合用于展现用户界面。WPF的用户界面是由一个"对象树"来构成的.这个树就是我们所说的逻辑树。 

        List 3.1中的代码定义了"About dialog",它使用Window元素作为逻辑树的根。Window控件内部包含一个子元素:StackPanel控件(第六章"Layout with Panels"将介绍),StackPanel内部还包含一个内部有两个Button控件的StackPanel。

       LISTING 3.1 A Simple About Dialog in XAML


    <Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    Title=”About WPF Unleashed” SizeToContent=”WidthAndHeight”
    Background=”OrangeRed”> 
        <StackPanel> 
            <Label FontWeight=”Bold” FontSize=”20” Foreground=”White”> 
                WPF Unleashed (Version 3.0) 
            </Label> 
            <Label>© 2006 SAMS Publishing</Label> 
            <Label>Installed Chapters:</Label> 
            <ListBox> 
                <ListBoxItem>Chapter 1</ListBoxItem> 
                <ListBoxItem>Chapter 2</ListBoxItem> 
            </ListBox> 
            <StackPanel Orientation=”Horizontal” HorizontalAlignment=”Center”> 
                <Button MinWidth=”75” Margin=”10”>Help</Button> 
                <Button MinWidth=”75” Margin=”10”>OK</Button> 
            </StackPanel> 
            <StatusBar>You have successfully registered this product.</StatusBar> 
        </StackPanel>
    </Window>

      图3.1是List 3.1中代码运行后的结果(你可以将里面的代码复制到XamlPad),图3.2是这个窗体所对应的逻辑树。
     
       FIGURE 3.1 The rendered dialog from Listing 3.1.

       需要注意的是:逻辑树并不只存在于使用XAML构建的对象中,使用程序代码构建的对象同样存在逻辑树。
      
    FIGURE 3.2 The logical tree for Listing 3.1.
       从图中可以看出,逻辑树的概念还是比较简单的。那我们为何还要这么关注逻辑树这个概念呢?这是因为逻辑树会在会多方面影响到WPF。如属性,事件,资源等。举个例子来说,属性的值会沿着逻辑树传递到子元素上;事件的触发也是沿着逻辑树传递的。这些例子我们会在后面讨论 

        和逻辑树类似的是视觉树。逻辑树中包含很多节点,这些节点对我们来说是个黑盒(black box)。视觉树是逻辑树的一种扩展,可以将逻辑树中的节点分解成核心的视觉组件,这样视觉树可以将这些黑盒的内部实现暴露给我们。举例来说,虽然一个的ListBox在逻辑上是一个单独的控件,但是从视觉树的角度上看,ListBox是由很多wpf的原始元素组成:一个Border,两个ScrollBars...  

       需要说明的是:并不是逻辑树中的每个节点都是视觉树,符合条件的只有那些继承子 System.WindowsMedia.Visual或者System.Windows.Media.Visual3D的元素。其他的元素并不包括在内,因为那些元素(包括简单的字符串内容)没有继承自身的呈现行为。 

          图3.3是List 3.1中代码在Windows Vista的Aero主题下运行时的视觉树。图中的一些组件是在运行时看不到的,例如ListBox控件的那两个ScrollBar,Label控件的Border.从图中我们可以看出Button,Label,ListBoxItem这些控件都是由相同的一些元素组成。当然,Button控件使用的是ButtonChorme元素而不是Border元素。(这些控件之所以看上去不同是因为属性的默认值不同。例如Button的Margin属性的默认值为10,10,10,10,而Label控件的Margio值都为0)
       
    FIGURE 3.3 The visual tree for Listing 3.1, with logical tree nodes emphasized.

          视觉树是相当复杂的,它是WPF底层架构中非常本质的部分,可以让我们对WPF的构成有深入的了解. 幸运的是,我们没必要对其过多关注,除非你要彻底地改变一个控件的样式(第10章“Styles, Templates, Skins, and Themes”会提到)或者做一些底层的绘图(第11章2D Graphics会提到)

    WARNING

    避免编写和特定视觉树紧密结合的代码,虽然视觉树不会因为添加删除元素的操作而改变,但当控件应用不同的主题时,同一个元素的视觉树是可能不同的


        我们使用System.Windows.LogicalTreeHelperSystem.Windows.Media.VisualTreeHelper类可以很容易分割逻辑树和视觉树。List 3.2中的代码是List 3.1的XAML代码的后台代码。调试程序时会以深度优先的方式展现窗体的逻辑树和视觉树。
       
       LISTING 3.2 Walking and Printing the Logical and Visual Trees


    using System;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Media;
    public partial class AboutDialog : Window


        public AboutDialog() 
            { 
                InitializeComponent(); 
                PrintLogicalTree(0, this); 
            } 

        protected override void OnContentRendered(EventArgs e) 
            { 
                base.OnContentRendered(e); 
                PrintVisualTree(0, this); 
            } 

        void PrintLogicalTree(int depth, object obj) 
            { 
                // Print the object with preceding spaces that represent its depth 
                Debug.WriteLine(new string(‘ ‘, depth) + obj); 
                // Sometimes leaf nodes aren’t DependencyObjects (e.g. strings) 
                if (!(obj is DependencyObject)) return; 
                    // Recursive call for each logical child 
                foreach (object child in LogicalTreeHelper.GetChildren( obj as DependencyObject))
                    PrintLogicalTree(depth + 1, child); 
            } 

        void PrintVisualTree(int depth, DependencyObject obj) 
            { 
                // Print the object with preceding spaces that represent its depth 
                Debug.WriteLine(new string(‘ ‘, depth) + obj); 
                // Recursive call for each visual child 
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
                    PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i)); 
            }
    }


     
           将窗体本身传递给方法后(PrintVisualTree和PrintLogicalTree),得到的是和图3.2和图3.3一样的结果,只不过是文本形式的。我们可以在Window的构造函调用PrintLogicalTree方法,对其逻辑树进行遍历。但是视觉树则需要整个窗体呈现后才能够遍历。所以我们才将PrintVisualTree方法放OnContentRendered方法内调用,而不是像PrintLogicalTree那样放在构造函数中。

            遍历任意一棵树时都可以使用树中元素的实例方法。例如,Visual类有三个保护成员(VisualParent,VisualChildrenCount和GetVisualChild),用于得到Visual对象的父和子。FrameworkElement是许多控件的基类。例如Button,Label都是它的子类。FrameworkElement定义了一个公共的属性:Parent。用于呈现逻辑上的父对象。而FrameworkElement的各个子类所暴露的逻辑子对象也各有不同。例如有的类的子类可以是集合,而有的类则暴露一个内容属性(Content property),强迫该元素只能包含一个逻辑子对象

           
            下一节将介绍Dependency Property,它是WPF非常重要的特性...
  • 相关阅读:
    apache安全—用户访问控制
    hdu 3232 Crossing Rivers 过河(数学期望)
    HDU 5418 Victor and World (可重复走的TSP问题,状压dp)
    UVA 11020 Efficient Solutions (BST,Splay树)
    UVA 11922 Permutation Transformer (Splay树)
    HYSBZ 1208 宠物收养所 (Splay树)
    HYSBZ 1503 郁闷的出纳员 (Splay树)
    HDU 5416 CRB and Tree (技巧)
    HDU 5414 CRB and String (字符串,模拟)
    HDU 5410 CRB and His Birthday (01背包,完全背包,混合)
  • 原文地址:https://www.cnblogs.com/stswordman/p/791654.html
Copyright © 2011-2022 走看看