在Silverlight项目开发中,经常会把一个独立功能的控件封装成一个UserControl,然后供其他页面或者控件进行调用。前一段时间,在项目中遇到一个问题,需要在同一个页面重复调用多个相同的UserControl控件,然后在父页面中控制这些重复生成的子控件。由于很多控件是动态
  
在Silverlight项目开发中,经常会把一个独立功能的控件封装成一个UserControl,然后供其他页面或者控件进行调用。前一段时间,在项目中遇到一个问题,需要在同一个页面重复调用多个相同的UserControl控件,然后在父页面中控制这些重复生成的子控件。由于很多控件是动态生成,数量也是动态控制,所以所有的操作都需要使用后台代码进行实现。
 
在上面的需求中需要用到Silverlight API中的VisualTreeHelper类,对于VisualTreeHelper类,有不少文章已经介绍过,该类可以对Silverlight可视化树进行遍历,该可视化树是逻辑对象树的一个子集。我们可以通过VisualTreeHelper提供的方法GetChild(),GetParent()和GetChildrenCount(),分别获取子控件,父控件以及子控件数量。
 
在实际项目中,为满足实际开发需求,对VisualTreeHelper的方法重新进行封装是非常必要的。
 
首先要介绍的Hleper方法是GetParentObject方法,获取父控件方法。该方法将根据当前控件,遍历查找其父控件是否存在。参数1是表示当前子控件名,参数2是要查询父控件名;使用VisualTreeHelper.GetParent方法获取当前父控件。
 
1
public
T GetParentObject
<
T
>
(DependencyObject obj,
string
name)
where
T : FrameworkElement
2
{
3
DependencyObject parent
=
VisualTreeHelper.GetParent(obj);
4
5
while
(parent
!=
null
)
6
{
7
if
(parent
is
T
&&
(((T)parent).Name
==
name
|
string
.IsNullOrEmpty(name)))
8
{
9
return
(T)parent;
10
}
11
12
parent
=
VisualTreeHelper.GetParent(parent);
13
}
14
15
return
null
;
16
}
17
 
 
另外一个Helper方法是GetChildObject,获取子控件方法。该方法将根据当前控件,遍历查找其子控件是否存在。参数1是表示当前父控件名,参数2是要查询子控件名;
 
1
public
T GetChildObject
<
T
>
(DependencyObject obj,
string
name)
where
T : FrameworkElement
2
{
3
DependencyObject child
=
null
;
4
T grandChild
=
null
;
5
6
for
(
int
i
=
0
; i
<=
VisualTreeHelper.GetChildrenCount(obj)
-
1
; i
++
)
7
{
8
child
=
VisualTreeHelper.GetChild(obj, i);
9
10
if
(child
is
T
&&
(((T)child).Name
==
name
|
string
.IsNullOrEmpty(name)))
11
{
12
return
(T)child;
13
}
14
else
15
{
16
grandChild
=
GetChildObject
<
T
>
(child, name);
17
if
(grandChild
!=
null
)
18
return
grandChild;
19
}
20
}
21
22
return
null
;
23
24
}
 
 
最后介绍一个Helper方法是GetChildObjects方法,该方法将把所有子控件作为List集合返回到客户端。其中第一个参数是父控件参数,而第二个参数是特定子控件名称,如果需要遍历全部子控件,第二个参数留空即可。
 
 
1
public
List
<
T
>
GetChildObjects
<
T
>
(DependencyObject obj,
string
name)
where
T : FrameworkElement
2
{
3
DependencyObject child
=
null
;
4
List
<
T
>
childList
=
new
List
<
T
>
();
5
6
for
(
int
i
=
0
; i
<=
VisualTreeHelper.GetChildrenCount(obj)
-
1
; i
++
)
7
{
8
child
=
VisualTreeHelper.GetChild(obj, i);
9
10
if
(child
is
T
&&
(((T)child).Name
==
name
||
string
.IsNullOrEmpty(name)))
11
{
12
childList.Add((T)child);
13
}
14
15
childList.AddRange(GetChildObjects
<
T
>
(child,
""
));
16
}
17
18
return
childList;
19
20
}
 
 
下面用一个例程演示使用方法:
 
使用方法很简单,首先创建基础控件:
 
1
<
UserControl
x:Class
="SLVisualTreeHelper.MainPage"
2
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
4
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
5
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
6
mc:Ignorable
="d"
7
d:DesignHeight
="300"
d:DesignWidth
="400"
>
8
9
<
Grid
x:Name
="LayoutRoot"
Background
="White"
>
10
<
Grid.RowDefinitions
>
11
<
RowDefinition
Height
="Auto"
></
RowDefinition
>
12
<
RowDefinition
Height
="*"
></
RowDefinition
>
13
</
Grid.RowDefinitions
>
14
<
StackPanel
x:Name
="spDemoPanel"
Orientation
="Vertical"
Grid.Row
="0"
>
15
<
TextBlock
Margin
="5"
>
获取子控件和父控件演示
</
TextBlock
>
16
<
TextBlock
Margin
="5"
>
专注Silverlight技术交流
</
TextBlock
>
17
<
TextBlock
Margin
="5"
>
博客:http//jv9.cnblogs.com
</
TextBlock
>
18
<
Button
x:Name
="btDemoButton"
Width
="120"
Height
="40"
Content
="获取所有控件"
Click
="btDemoButton_Click"
HorizontalAlignment
="Left"
Margin
="5"
/>
19
<
Button
x:Name
="btModifyChild"
Width
="120"
Height
="40"
Content
="修改布局控件背景"
Click
="btModifyChild_Click"
HorizontalAlignment
="Left"
Margin
="5"
/>
20
<
Button
x:Name
="btModifyChilds"
Width
="120"
Height
="40"
Content
="批量修改控件字体尺寸"
Click
="btModifyChilds_Click"
HorizontalAlignment
="Left"
Margin
="5"
/>
21
</
StackPanel
>
22
23
<
StackPanel
x:Name
="spResult"
Grid.Row
="1"
>
24
<
TextBlock
x:Name
="tbResult"
/>
25
</
StackPanel
>
26
27
</
Grid
>
28
</
UserControl
>
29
 
 
然后在后台代码,声明实例进行调用,
 
1
namespace
SLVisualTreeHelper
2
{
3
public
partial
class
MainPage : UserControl
4
{
5
6
public
MainPage()
7
{
8
InitializeComponent();
9
}
10
11
private
void
btDemoButton_Click(
object
sender, RoutedEventArgs e)
12
{
13
Globals VTHelper
=
new
Globals();
14
StackPanel sp
=
VTHelper.GetChildObject
<
StackPanel
>
(
this
.LayoutRoot,
"
spDemoPanel
"
);
15
Grid layoutGrid
=
VTHelper.GetParentObject
<
Grid
>
(
this
.spDemoPanel,
"
LayoutRoot
"
);
16
List
<
TextBlock
>
textblock
=
VTHelper.GetChildObjects
<
TextBlock
>
(
this
.LayoutRoot,
""
);
17
18
19
if
(sp
!=
null
)
20
{
21
if
(layoutGrid
!=
null
)
22
{
23
24
if
(textblock.Count
>
0
)
25
{
26
tbResult.Text
=
"
包含TextBlock控件数量为:
"
+
textblock.Count.ToString()
+
"
\n
"
;
27
}
28
tbResult.Text
+=
"
获取父控件成功....\n
"
;
29
}
30
tbResult.Text
+=
"
获取子控件成功....\n
"
;
31
}
32
}
33
34
private
void
btModifyChild_Click(
object
sender, RoutedEventArgs e)
35
{
36
Globals VTHelper
=
new
Globals();
37
StackPanel sp
=
VTHelper.GetChildObject
<
StackPanel
>
(
this
.LayoutRoot,
"
spDemoPanel
"
);
38
sp.Background
=
new
SolidColorBrush(Colors.Purple);
39
}
40
41
private
void
btModifyChilds_Click(
object
sender, RoutedEventArgs e)
42
{
43
Globals VTHelper
=
new
Globals();
44
List
<
TextBlock
>
textblock
=
VTHelper.GetChildObjects
<
TextBlock
>
(
this
.LayoutRoot,
""
);
45
foreach
(TextBlock tmpTextblock
in
textblock)
46
{
47
tmpTextblock.FontSize
+=
6
;
48
}
49
}
50
}
51
}
 
 
其中Globals类中包含前文介绍的几个获取代码。
 
在线演示:
 
 
 
最后是源代码下载,项目是VS2010+Silverlight 4,