As a programmer, you may have situations where you need a handle to a control to set its property programmatically. Pretty simple right? Let’s add some complexity. What if you are not guaranteed to know exactly where the control resides. Is it in our Grid at child index 0 or is it in a StackPanel within the Grid? What if we want to set the background of all Canvas objects on our page to Transparent?
The Silverlight API provides the VisualTreeHelper class to assist with the traversal of the visual object tree. Silverlight has a logical and visual object tree. The visual tree is a subset of the logical object tree and is only populated by objects that have rendering implications. In a general sense, a collection class would not be included in the visual tree however the Grid you are using as your LayoutRoot of your page would be. The VisualTreeHelper class has 3 methods to assist with the visual object tree: GetChild(), GetChildrenCount(), GetParent(). Their names are self-descriptive and what I’d like to do is create a few recursive helper methods/extensions to these methods that are a bit more powerful.
This method returns the first parent of a given type and/or name of an object’s parent hierarchy. For instance, let’s say you know that our StackPanel resides somewhere in the bowels of a Grid named LayoutRoot. To get a handle to LayoutRoot we could do the following:
This method returns the first child of a given type and/or name of an object’s child hierarchy. So let’s take the inverse of the above. We have a StackPanel named myStackPanel that resides somewhere beneath our Grid LayoutRoot. The get the handle to myStackPanel we could do the following:
This method returns a list collection of all children of a given type and/or name of an object’s child hierarchy. So let’s say we want all rectangles which reside somewhere on our page. Again, our page has a Grid named LayoutRoot. We could get a list collection of all rectangles on the page by making the following call:
Below is the actual methods’ code. I’m also attaching my zipped test solution.
1: Module Common
2: ''' <summary>
3: ''' Navigates up the object's parent hierarchy and returns the first parent match of the specified type and/or object name.
4: ''' </summary>
5: ''' <typeparam name="T"></typeparam>
6: ''' <param name="obj"></param>
7: ''' <param name="name"></param>
8: ''' <returns></returns>
9: ''' <remarks></remarks>
10: Public Function GetParentObject(Of T As FrameworkElement)(ByVal obj As DependencyObject, Optional ByVal name As String = "") As T
11: Dim parent As DependencyObject = VisualTreeHelper.GetParent(obj)
12:
13: While parent IsNot Nothing
14: If TypeOf parent Is T AndAlso (CType(parent, T).Name = name Or String.IsNullOrEmpty(name)) Then
15: Return CType(parent, T)
16: End If
17:
18: parent = VisualTreeHelper.GetParent(parent)
19: End While
20:
21: Return Nothing
22: End Function
23:
24: ''' <summary>
25: ''' Recursively searches an object's child hierarchy and returns the first child match of the specified type and/or object name.
26: ''' </summary>
27: ''' <typeparam name="T"></typeparam>
28: ''' <param name="obj"></param>
29: ''' <param name="name"></param>
30: ''' <returns></returns>
31: ''' <remarks></remarks>
32: Public Function GetChildObject(Of T As FrameworkElement)(ByVal obj As DependencyObject, Optional ByVal name As String = "") As T
33: Dim child As DependencyObject = Nothing, grandChild As T = Nothing
34:
35: For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
36: child = VisualTreeHelper.GetChild(obj, i)
37:
38: If TypeOf child Is T AndAlso (CType(child, T).Name = name Or String.IsNullOrEmpty(name)) Then
39: Return CType(child, T)
40: Else
41: grandChild = GetChildObject(Of T)(child, name)
42: If grandChild IsNot Nothing Then Return grandChild
43: End If
44: Next
45:
46: Return Nothing
47: End Function
48:
49: ''' <summary>
50: ''' Recursively searches an object's child hierarchy and returns the all children that are of the specified type and/or object name.
51: ''' </summary>
52: ''' <typeparam name="T"></typeparam>
53: ''' <param name="obj"></param>
54: ''' <param name="name"></param>
55: ''' <returns></returns>
56: ''' <remarks></remarks>
57: Public Function GetChildObjects(Of T As FrameworkElement)(ByVal obj As DependencyObject, Optional ByVal name As String = "") As List(Of T)
58: Dim child As DependencyObject = Nothing, childList As List(Of T) = New List(Of T)
59:
60: For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
61: child = VisualTreeHelper.GetChild(obj, i)
62:
63: If TypeOf child Is T AndAlso (CType(child, T).Name = name Or String.IsNullOrEmpty(name)) Then
64: childList.Add(CType(child, T))
65: End If
66:
67: childList.AddRange(GetChildObjects(Of T)(child))
68: Next
69:
70: Return childList
71: End Function
72: End Module