WPF自学(二)-WPF逻辑树和可视树

本文

可视化树

可视化树代表你界面上所有的渲染在屏幕上的元素。可视化树用于渲染,事件路由,定位资源(如果该元素没有逻辑父元素)等等等等。向上或者乡下遍历可视化树可以简单的使用VisualTreeHelper和简单的递归方法。

例如:


DependencyObject FindVisualTreeRoot (DependencyObject initial)
{
 DependencyObject current = initial;
 DependencyObject result = initial;

 

 While(current !=null)
 {
  result = current;
  if(current is Visual || current is Visual3D)
  {
   current = VisualTreeHelper.GetParent(current);
  }
  else
  {
   current = LogicalTreeHelper.GetParent(current);
  }
 }
 return result;
}      

  

作用:

这段代码在必要的时候沿着逻辑树上溯,如else子句所示。这很有用,假如说用户点击一个在TextBlock中的Run元素你需要从Run元素开始上溯可视化树。由于Run类继承自ContentElement, 所以它不真在可视化树中。所以我们需要走出逻辑树直到我们找到了那个包好Run元素的TextBlock。之后我们就可以回到可视化树上来了,因为TextBlock不是ContentElement的子类。

 

逻辑树

逻辑树表示UI的核心结构。和XAML文件中定义的元素近乎相等,排除掉内部生成的那些用来帮助渲染的可视化元素。WPF用逻辑树来决定依赖属性,值继承,资源解决方案等。
逻辑树用起来不像可视化树那么简单。对于新手来说,逻辑树可以包含类型对象,这一点和可视化树不同,可视化树只包含Dependancy子类的实例。遍历逻辑树时,要记住逻辑树的叶子可以是任何类型。由于LogicTreeHelper只对DependencyObject有效,遍历逻辑树时需要非常小心,最好做类型检查。看个例子:
 

void WalkDownLogicalTree(object current)
{
 DoSomethingWithObjectInLogicalTree(current);
 DependencyObject depObj = current as DependencyObject;
 if(depObj != null)
 {
  foreach(object logicalChild in LogicalTreeHelper.GetChildren(depObj))
   WalkDownLogicalTree(logicalChild);
 }
}

 

 

 

 

一个给定的Window/Page/Control会有一棵视觉树,但是可以有几个逻辑树。这些逻辑树互相不相连。可以仅仅使用LogicalTreeHelper来在几棵逻辑树之间遍历。在这篇文章中,我会把顶层控件的逻辑树称作主逻辑树,在他里面的其他逻辑树称作逻辑岛。逻辑岛实际上就是普通的逻辑树但是“岛”可以帮助说明它们和主逻辑树并不相连。
这种无关性可以归结于一个概念:模板。
控件和数据对象本身并没有可见的外观。相反,它们依赖模板来决定怎样进行渲染。一个模板就像一个“拼图块”可以扩展开来以便展示正真的用来渲染的可视元素。这些元素是可扩展模板的一部分,称之为“模板元素”。这些元素有自己的逻辑树,和生成这些元素的对象所拥有的逻辑树不相连。这些小的逻辑树就是我说的逻辑岛。
你只能写额外的代码来在不同的逻辑树或者逻辑岛之间进行切换。遍历逻辑树时,为了连接这些岛,需要使用类似FrameworkElement.TemplateParent,FrameworkContentElement.TemplateParent这些属性来返回持有这些模板的元素,这样就把逻辑岛包含进来了。以下是找到任意元素
的TemplateParent的一个方法:

DependencyObject GetTemplatedParen(DependencyObject depObj)
{
 FrameworkElement fe = depObj as FrameworkElement;
 FrameworkElementElement fce = depObj as FrameworkContentElement;

DependencyObject result;

 if(fe != null)
  result = fe.TemplatedParent;

 else if(fce != null)
  result = fce.TemplateParent;
 else
  return null;

 return result;
}

 

 

 


下溯逻辑树并且在逻辑树之间切换更难因为TemplatedChild属性并不存在。你得检查逻辑树叶子元素的可视化子元素,然后看看这些子元素是不是别的逻辑树的成员。代码留给大家自己练习。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值