Tuesday, September 20, 2011

Traversing the Visual Tree in Silverlight

I recently had a problem where I had to find user controls within a ListBox. I was dismayed to find that there were no jQuery or LINQ style methods for traversing the visual tree in Silverlight! (Or at least I couldn't find anything.)


I discovered a workaround here.


In my case, I had to take it a step further, because I wanted all the controls that implemented a particular interface. I added one line of code and now it looks like this:


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 the types match or the type implements the interface type
            if (child.GetType() == targetType ||
                child.GetType().GetInterfaces().Contains(targetType))
            {
                children.Add(child);
            }
            GetChildren(child, targetType, ref children);
        }
    }
}
In use it looks like this:

private void SetExpanderStateForCategoryControls(ExpanderState expanderState)
{
    bool isExpanded = false;
    if (expanderState == ExpanderState.Expanded)
        isExpanded = true;
    if (expanderState == ExpanderState.Collapsed)
        isExpanded = false;
 
    List<UIElement> categoryControls = new List<UIElement>();
    GetChildren(GeneralProfileSlotsListBox, typeof(ICategoryControl), ref categoryControls);
    GetChildren(BioProfileSlotsListBox, typeof(ICategoryControl), ref categoryControls);
    foreach (ICategoryControl categoryControl in categoryControls)
    {
        categoryControl.IsExpanded = isExpanded;
    }
}
EDIT: I managed to condense the use case quite a bit. I didn't need to loop thru the list box items to search for the controls I was looking for.