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