VisualTreeHelper Class in Silverlight

by mgordon 20. February 2009 08:37

It’s hard for me to believe I’d never encountered the situation before, but I was recently working on a part of a Silverlight application where I’d used a ListBox and specified an ItemTemplate within it containing a CheckBox and a TextBlock.  When a particular event fired, I wanted to iterate through all the ListBox Items, examine the Text property of the TextBlock and based on some simple logic, either check or uncheck the CheckBox.  My XAML for the ListBox looked like this:

<ListBox Margin="-5.057,34.225,0.116,0.121" Grid.Row="1" x:Name="lbRoles">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal" >
                <CheckBox Checked="CheckBox_Checked"></CheckBox>
                <TextBlock Margin="5,0,0,0" Text="{Binding Path=RoleName}" FontWeight="Bold" 
Width="Auto" HorizontalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight" LineHeight="15"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

So, basically, I was binding the ListBox to a collection and populating the TextBlock’s Text property from the binding.  My first task was to figure out how to access the ListBoxItem’s since The ListBox’s Items property would return the collection it was bound to and not the generated Items. I did some research and came across a newsgroup thread, here that contains an example of using the VisualTreeHelper class

In that thread, there is method defined like so:

private void GetChildren(UIElement parent, Type targetType, ref List<UIElement> children)
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    if (count > 0)
    {
        for (int i = 0; i < count; i++)
        {
            UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
            if (child.GetType() == targetType)
            {
                children.Add(child);
            }
            GetChildren(child, targetType, ref children);
        }
    }
}


You’ll notice that the method requires you to specify a type of control you’re interested in and also that it uses recursion to walk through every control in the visual tree beneath the specified parent.  I quickly found there is a vast hierarchy of controls created for the ListBox beyond what you’ll see in your XAML so it makes sense to recurse the tree of controls and only return what you’re needing.  I added this method to my class and used it for the above described problem like this:

List<UIElement> items = new List<UIElement>();
GetChildren(lbRoles, typeof(ListBoxItem), ref items);

foreach (ListBoxItem item in items)
{
    List<UIElement> children = new List<UIElement>();
    GetChildren(item, typeof(CheckBox), ref children);
    CheckBox cb = (CheckBox)children[0];

    children.Clear();
    GetChildren(item, typeof(TextBlock), ref children);
    TextBlock block = (TextBlock)children[0];

    if (_currentUserRoles.Contains(block.Text))
    {
        cb.IsChecked = true;
    }
    else
    {
        cb.IsChecked = false;
    }
}

So, using VisualTreeHelper and the helper method, I’m able to iterate through all the ListBoxItems and within each, to get a reference to the CheckBox and TextBlock within it.

Tags:

Silverlight | .Net

Comments are closed

About the author

Mitch Gordon lives and works in the great state of Georgia.

RecentPosts

Month List