WPF 逻辑树与视觉树。

https://msdn.microsoft.com/zh-cn/library/ms753391

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

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

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

 

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

 

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

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

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

 

逻辑树用途


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

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

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

 

重写逻辑树(所以说罗辑树遍历的是所有 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();}
    }
}

 

posted @ 2017-03-28 11:04  高_山_流_水  阅读(597)  评论(0)    收藏  举报