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用于获取某对象的上级子对象
测试代码:
<
UserControl
x:Class
="ToolsTest.MainPage"
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.Linq;
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