How to expand all nodes of a WPF treeview in code behind?

WPF doesn't have an ExpandAll method. You'll need to loop through and set the property on each node.

See this question or this blog post.


After playing around with all of the various methods for fully expanding and collapsing a tree view, by far the fastest method is the following. This method seems to work on very large trees.

Ensure your tree is virtualized, if it isn't virtualized then as soon as the tree gets to any kind of size it is going to become painfully slow whatever you do.

VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"

Assume that you have a view model backing your tree, each node on that view model that corresponds to a HierarchicalDataTemplate needs an IsExpanded property (it doesn't need to implement property changed). Assume these view models implement an interface like this:

interface IExpandableItem : IEnumerable
{
    bool IsExpanded { get; set; }
}

The TreeViewItem style needs to be set as follows to bind the IsExpanded property in the view model to the view:

<Style
    TargetType="{x:Type TreeViewItem}">
    <Setter
        Property="IsExpanded"
        Value="{Binding
            IsExpanded,
            Mode=TwoWay}" />
</Style>

We are going to use this property to set the expansion state, but also, because the tree is virtualized this property is necessary to maintain the correct view state as the individual TreeViewItems get recycled. Without this binding nodes will get collapsed as they go out of view as the user browses the tree.

The only way to get acceptable speed on large trees is to work in code behind in the view layer. The plan is basically as follows:

  1. Get hold of the current binding to the TreeView.ItemsSource.
  2. Clear that binding.
  3. Wait for the binding to actually clear.
  4. Set the expansion state in the (now unbound) view model.
  5. Rebind the TreeView.ItemsSource using the binding we cached in step 1.

Because we have virtualization enabled, performing a bind on TreeView.ItemsSource turns out to be very fast, even with a large view model. Likewise, when unbound updating the expansion state of the nodes should be very fast. This results in surprisingly fast updates.

Here is some code:

void SetExpandedStateInView(bool isExpanded)
{
    var model = this.DataContext as TreeViewModel;
    if (model == null)
    {
        // View model is not bound so do nothing.
        return;
    }

    // Grab hold of the current ItemsSource binding.
    var bindingExpression = this.TreeView.GetBindingExpression(
        ItemsControl.ItemsSourceProperty);
    if (bindingExpression == null)
    {
        return;
    }

    // Clear that binding.
    var itemsSourceBinding = bindingExpression.ParentBinding;
    BindingOperations.ClearBinding(
    this.TreeView, ItemsControl.ItemsSourceProperty);

    // Wait for the binding to clear and then set the expanded state of the view model.
    this.Dispatcher.BeginInvoke(
        DispatcherPriority.DataBind, 
        new Action(() => SetExpandedStateInModel(model.Items, isExpanded)));

    // Now rebind the ItemsSource.
    this.Dispatcher.BeginInvoke(
        DispatcherPriority.DataBind,
        new Action(
            () => this.TreeView.SetBinding(
                ItemsControl.ItemsSourceProperty, itemsSourceBinding)));
}

void SetExpandedStateInModel(IEnumerable modelItems, bool isExpanded)
{
    if (modelItems == null)
    {
        return;
    }

    foreach (var modelItem in modelItems)
    {
        var expandable = modelItem as IExpandableItem;
        if (expandable == null)
        {
            continue;
        }

        expandable.IsExpanded = isExpanded;
        SetExpandedStateInModel(expandable, isExpanded);
    }
}

In xaml you could do it as follows :

 <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="TreeViewItem.IsExpanded" Value="True"/>
            </Style>
 </TreeView.ItemContainerStyle>