对于  LogicalTree   VisualTree  都是对  Children的新增及访问来实现一个图的构成的。

WPF 中,最完整的树结构是对象树。

可视化树描述由 Visual 基类表示的可视化对象的结构,我相信实现方式与逻辑树相类似。

 

“树”形式路由事件的路由

 


如前所述,对于任何给定的路由事件,其路由都沿着一条预定的树路径进行,这棵树是可视化树和逻辑树表示形式的混合体。  事件路由可在树中向上或向下进行,具体取决于该事件是隧道路由事件还是冒泡路由事件。  事件路由概念没有直接支持的帮助器类,因此当出现引发实际路由的事件时,无法使用这种类来遍历事件路由。  存在表示路由的类 EventRoute,但该类的方法通常仅供内部使用。 

资源字典和树

 


对页中定义的所有 Resources 进行资源字典查找时,基本上是在遍历逻辑树。  逻辑树之外的对象可以引用键控资源,但资源查找顺序将从该对象与逻辑树的连接处开始。  在 WPF 中,只有逻辑树节点可以有包含 ResourceDictionary 的 Resources 属性,因此,通过遍历可视化树从 ResourceDictionary 中查找键控资源并无益处。 

但是,资源查找也可以超出直接逻辑树。  对于应用程序标记,资源查找可向前继续进行到应用程序级资源字典,然后再到作为静态属性或键进行引用的主题支持和系统值。  如果资源引用是动态的,则主题本身也可以引用主题逻辑树之外的系统值。  有关资源字典和查找逻辑的更多信息,请参见XAML 资源。

 

逻辑树用途


有了逻辑树的存在,内容模型可以方便地循环访问其潜在子对象,因而可以得到扩展。  此外,逻辑树还为某些通知提供框架,例如在加载逻辑树中的所有对象之后。  从根本上说,逻辑树是框架级别的近似运行时对象图(排除了可视化对象),但其足以用于对您自己的运行时应用程序成分执行多种查询操作。 

此外,静态和动态资源引用有着相同的解析过程:针对最初发出请求的对象,沿逻辑树向上查找 Resources 集合,然后沿逻辑树继续向上,检查每一个 FrameworkElement 或 FrameworkContentElement,查找另一个包含 ResourceDictionary(因而可能包含该键)的 Resources 值。  当同时存在逻辑树和可视化树时,将使用逻辑树进行资源查找。  有关资源字典和查找的更多信息,请参见XAML 资源。 

逻辑树的构成


逻辑树在 WPF 框架级别定义。这意味着,与逻辑树操作关系最密切的 WPF 基元素是 FrameworkElement 或 FrameworkContentElement。  但是可以看出,如果实际使用 LogicalTreeHelper API,则逻辑树有时会包含既不是 FrameworkElement,也不是 FrameworkContentElement 的节点。  例如,在逻辑树中可以看到 TextBlock 的 Text 值,该值是一个字符串。

 

重写逻辑树(所以说罗辑树遍历的是所有 FrameworkElement、 FrameworkContentElement 中的Children, Items等集合  。LogicalTreeHelper)

public class SingletonPanel : StackPanel
{
    //private UIElementCollection _children; 
    private FrameworkElement _child;

    public SingletonPanel() {

    }

    public FrameworkElement SingleChild
    {

        get { return _child;}
        set
        {
            if (value==null) {
                 RemoveLogicalChild(_child);
            } else {             
                 if (_child==null) {
                     _child = value;
                 } else {
                     // raise an exception?
                     MessageBox.Show("Needs to be a single element");
                 }
            }
        } 
    }
    public void SetSingleChild(object child)
    {
        this.AddLogicalChild(child);
    }

    public new void AddLogicalChild(object child)
    {
        _child = (FrameworkElement)child;
        if (this.Children.Count == 1)
        {
            this.RemoveLogicalChild(this.Children[0]);
            this.Children.Add((UIElement)child);
        }
        else
        {
            this.Children.Add((UIElement)child);
        }
    }

    public new void RemoveLogicalChild(object child)

    {
        _child = null;
        this.Children.Clear();
    }
    protected override IEnumerator LogicalChildren
    {
       get {
       // cheat, make a list with one member and return the enumerator
       ArrayList _list = new ArrayList();
       _list.Add(_child);
       return (IEnumerator) _list.GetEnumerator();}
    }
}