在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.