有没有办法折叠TreeView中的子树?

时间:2012-05-17 18:47:37

标签: c# wpf user-interface

我正在尝试向TreeView添加功能,其中用户可以通过单击按钮扩展和折叠所有节点。 Expand使用ExpandSubTree可以很好地运行。无论出于何种原因,都没有CollapseSubTree功能。我怎样才能成功完成这项任务?

这是我目前的职能:

private void expand_collapse_children(TreeViewItem tvi, bool expand)
{
    if (tvi.Items.Count > 0)
    {
        foreach (TreeViewItem item in tvi.Items)
        {
            if (expand)
            {
                item.ExpandSubtree();
            }
            else
            {
                expand_collapse_children(item, expand);
                item.IsExpanded = false;
            }
        }
    }
}

作为注释:isExpanded比无用的步骤高出半步。我可以在它为真时将其设置为false,并且它不会折叠超过所选的最高级别。

谢谢!

4 个答案:

答案 0 :(得分:1)

如果您有兴趣,这里是实现ExpandSubTree的实现(来自Reflector)。我想你可以采取相反的方式。

public void ExpandSubtree()
{
    ExpandRecursive(this);
}

private static void ExpandRecursive(TreeViewItem item)
{
    if (item != null)
    {
        if (!item.IsExpanded)
        {
            item.SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.TrueBox);
        }
        item.ApplyTemplate();
        ItemsPresenter presenter = (ItemsPresenter) item.Template.FindName("ItemsHost", item);
        if (presenter != null)
        {
            presenter.ApplyTemplate();
        }
        else
        {
            item.UpdateLayout();
        }
        VirtualizingPanel itemsHost = item.ItemsHost as VirtualizingPanel;
        item.ItemsHost.EnsureGenerator();
        int index = 0;
        int count = item.Items.Count;
        while (index < count)
        {
            TreeViewItem item2;
            if (itemsHost != null)
            {
                itemsHost.BringIndexIntoView(index);
                item2 = (TreeViewItem) item.ItemContainerGenerator.ContainerFromIndex(index);
            }
            else
            {
                item2 = (TreeViewItem) item.ItemContainerGenerator.ContainerFromIndex(index);
                item2.BringIntoView();
            }
            if (item2 != null)
            {
                ExpandRecursive(item2);
            }
            index++;
        }
    }
}

答案 1 :(得分:1)

我实现扩展TreeView中的所有节点,如下所示(我有一个类似的功能来折叠所有节点):

foreach (var treeViewItem in MyTreeView.FindVisualDescendants<TreeViewItem>(e => !e.IsExpanded, true)) {
  treeViewItem.IsExpanded = true;
}

FindVisualDescendants是一个方便的扩展方法:

public static IEnumerable<T> FindVisualDescendants<T>(this Visual parent, Func<T, bool> predicate, bool deepSearch) where T : Visual {
  var visualChildren = new List<Visual>();
  var visualChildrenCount = VisualTreeHelper.GetChildrenCount(parent);
  for (var childIndex = 0; childIndex < visualChildrenCount; childIndex++) {
    visualChildren.Add((Visual) VisualTreeHelper.GetChild(parent, childIndex));
  }

  foreach (var child in visualChildren) {
    var typedChild = child as T;
    if ((typedChild != null) && (predicate == null || predicate.Invoke(typedChild))) {
      yield return typedChild;
      if (deepSearch) {foreach (var foundVisual in FindVisualDescendants(child, predicate, true)) {
        yield return foundVisual;
      }
    } else {
      foreach (var foundVisual in FindVisualDescendants(child, predicate, deepSearch)) {
        yield return foundVisual;
      }
    }
  }

  yield break;
}

答案 2 :(得分:1)

private static void CollapseRecursive(TreeViewItem item)
{
    // Collapse item if expanded.
    if (item.IsExpanded)
    {
        item.IsExpanded = false;
    }

    // If the item has sub items...
    if (item.Items.Count > 0)
    {
        // ... iterate them...
        foreach (TreeViewItem subItem in item.Items)
        {
            // ... and if they themselves have sub items...
            if (subItem.Items.Count > 0)
            {
                // ... collapse the sub item and its sub items.
                CollapseRecursive(subItem);
            }
        }
    }
}

答案 3 :(得分:1)

要获取ItemHost并调用EnsureGenerator,您将需要反射,因为这些是内部的:

var panel = (Panel)typeof(MultiSelector).InvokeMember("ItemsHost", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, item, null);

typeof (Panel).InvokeMember("EnsureGenerator", BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance, null, panel, null);