Question

I have a TreeView that is databound. I would like to expand the TreeViewItems but only to a depth of lets say 3.

Normally I would issue a TreeViewItem.ExpandSubtree() but that expands everything so I took a stab making my own as it should be fairly simple right?

Here is what I tried, I made the method below and then pass my treeviews ItemContainerGenerator to it and the items collection from the treeview, with a depth of 3.

private void ExpandTree(ItemContainerGenerator gen, ItemCollection items, int depth)
{
    depth--;
    foreach (var item in items)
    {
        TreeViewItem itm = (TreeViewItem)gen.ContainerFromItem(item);
        if (itm == null) continue;
        itm.IsExpanded = true;


        if(depth!=0 && itm.Items.Count > 0) ExpandTree(itm.ItemContainerGenerator,itm.Items,depth);
    }
}

The problem is that the first time it recursively calls back the ItemContainerGenerator for all subitems has a status of "NotStarted" and returns null every time it is called. While I trap the null it means that the tree only opens to a depth of 1 and not the 3 I wanted.

What am I missing here?

Was it helpful?

Solution

You are missing a delay to give the child ItemContainerGenerator time to create the grandchildren. The solution is to ask the WPF dispatcher to schedule the recursive call after the data binding infrastructure has had time to run:

Action recurse = () => ExpandTree(itm.ItemContainerGenerator, itm.Items, depth);
itm.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, recurse);  // note the priority

Now, by the time the delegate gets called, the ItemContainerGenerator will have had time to run, and the containers will be available.

You could probably also do this by subscribing to the child ItemContainerGenerator's StatusChanged event (and making the recursive call from there), but I haven't tried this approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top