对于 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();}
}
}