Silverlight中只有可视化树,没有WPF中的逻辑树,这一点可从SL的sdk文档中得到印证:
可视化树概念也存在于 WPF 中,它与 Silverlight 的可视化树概念类似。然而,一个显著的差异是 WPF 还提供一个附加的筛选器或对象树(称为"逻辑树")的概念。逻辑树概念与某些属性系统行为相关。Silverlight 不通过帮助器类来公开此逻辑树。Silverlight 中的确存在某些(但并非所有)相关的属性行为,但由于没有用于访问这些行为的帮助器 API,因此,逻辑树概念在 Silverlight 中将没有用武之地,因此本文档不讨论它。缺少逻辑树而引发的一个很小的兼容性问题是:FrameworkElement..::..Parent 属性行为在 Silverlight 版本 3 中是不同的,它实际上报告可视化树父项。
利用XamlPad,可以查看简单xaml(指不加载第三方程序集的xaml)的对象树:
xamlpad程序安装silverlight的sdk后,默认安装于x:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\下
如下图:
从上图可以看到,一个普通的Button控件,在可视化(对象)树里表现为:ButtomChrome,ContentPresenter,TextBlock的组合
另外Silverlight中提供了一个VisualTreeHelper工具类,用于操作可视化树,里面有4个静态方法:
官方解释如下:
FindElementsInHostCoordinates 检索一组对象,这些对象位于某一对象的坐标空间的指定点或 Rect 内。
GetChild 使用提供的索引,通过检查可视化树获取所提供对象的特定子对象。
GetChildrenCount 返回在可视化树中在某一对象的子集合中存在的子级的数目。
GetParent 返回可视化树中某一对象的父对象。
通俗点说:FindElementsInHostCoordinates常用于对象的碰撞检测,GetChild用于获取下级子对象(注意仅仅是下级,而非所有子对象,如果要获取所有子对象,需要自己写代码遍历),GetChildrenCount用于获取下级子对象的个数,GetParent用于获取某对象的上级子对象
测试代码:
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable ="d" d:DesignWidth ="640" d:DesignHeight ="480" >
< Grid x:Name ="LayoutRoot" >
< StackPanel x:Name ="sp" HorizontalAlignment ="Left" >
< TextBlock Text ="Test TextBlock" Height ="25" Width ="100" x:Name ="txt" ></ TextBlock >
< Button x:Name ="btn1" Content ="button1" Height ="25" Width ="100" ></ Button >
< StackPanel x:Name ="sp2" >
< Button x:Name ="btn2" Content ="button2" Height ="25" Width ="100" ></ Button >
</ StackPanel >
< Button x:Name ="btn3" Content ="button3" ></ Button >
</ StackPanel >
< Button x:Name ="btnClick" Content ="Test" Height ="22" Width ="80" HorizontalAlignment ="Center" VerticalAlignment ="Bottom" Click ="btnClick_Click" ></ Button >
</ Grid >
</ UserControl >
using System.Windows;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
namespace ToolsTest
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btnClick_Click( object sender, RoutedEventArgs e)
{
int _childCount = VisualTreeHelper.GetChildrenCount( this );
MessageBox.Show( " MainPage下级子对象总数: " + _childCount.ToString()); // 就是一个Grid,所以返回1
IEnumerable < Button > AllButtons = FindChildren < Button > ( this ); // 得到所有的Buttons
int i = 0 ;
foreach (Button btn in AllButtons)
{
i ++ ;
MessageBox.Show( string .Format( " 第{0}个按钮[{1}]的内容为:{2} " ,i,btn.Name,btn.Content));
}
StackPanel sp = VisualTreeHelper.GetParent(btn2) as StackPanel;
MessageBox.Show( string .Format( " {0}的上级对象是{1} " ,btn2.Content,sp.Name));
Rect rect = new Rect( 0 , 0 , 100 , 25 );
IEnumerable < UIElement > check = VisualTreeHelper.FindElementsInHostCoordinates(rect, this ); // 检测MainPage的0,0到100,25矩形区域内有哪些元素
foreach (UIElement item in check)
{
string _name = item.GetValue(NameProperty).ToString();
if (_name.Length > 0 )
{
MessageBox.Show(_name);
}
}
}
/// <summary>
/// 来自博客园"木野狐"的特定类型子对象方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="parent"></param>
/// <returns></returns>
public IEnumerable < T > FindChildren < T > (DependencyObject parent) where T : class
{
var count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0 )
{
for (var i = 0 ; i < count; i ++ )
{
var child = VisualTreeHelper.GetChild(parent, i);
var t = child as T;
if (t != null )
yield return t;
var children = FindChildren < T > (child);
foreach (var item in children)
yield return item;
}
}
}
}
}
最后关于对象碰撞检测,推荐一篇不错的文章: http://www.andybeaulieu.com/Home/tabid/67/EntryID/160/Default.aspx 里面对于矢量对象的检测就是利用的FindElementsInHostCoordinates