我正在构建一个在树视图中显示数据的WPF应用程序 . TreeView的ItemsSource是一个分组的CollectionViewSource . 我正在使用HierarchicalDataTemplate来渲染树的节点 . 所有这一切都很有效 . 但是,我正在努力使用树中的自动扩展/折叠节点 . 我需要两件事:1)能够单击按钮并自动展开/折叠树中的所有节点 . 我有这部分工作 . 2)单击一个节点时,我需要在树下展开第一个子节点并自动选择第一个项目 . 要清楚,这是我想要做的:

enter image description here

我已经搜索谷歌和SO高低几天,但没有提出任何运作良好的东西 . 我很确定我需要使用LogicalTreeHelper或VisualTreeHelper来找到正确的节点,但似乎无法弄明白 . 无论如何,这是我迄今为止所拥有的......

XAML:

<Window x:Class="WpfApplication4.MainWindow2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication4"
    Title="MainWindow" Height="400" Width="500">

<Window.Resources>
    <local:DocumentViewModel x:Key="documents" />

    <CollectionViewSource Source="{Binding Source={StaticResource documents}, Path=People}" x:Key="DocumentCVS">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Encounter" />
            <PropertyGroupDescription PropertyName="Title" />
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

    <DataTemplate x:Key="documentTemplate">
        <TextBlock Text="{Binding Path=Subtitle}"/>
    </DataTemplate>

    <HierarchicalDataTemplate x:Key="level2Template" ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource documentTemplate}">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="level1Template" ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource level2Template}">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
    </HierarchicalDataTemplate>
</Window.Resources>

<DockPanel>
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
        <Button Name="Expand_Button" Content="Expand All" Padding="5" Margin="5" Click="Expand_Button_Click" />
        <Button Name="Collapse_Button" Content="Collapse All" Padding="5" Margin="5" Click="Collapse_Button_Click" />
        <Button Name="Invert_Button" Content="Invert All" Padding="5" Margin="5" Click="Invert_Button_Click" />
    </StackPanel>

    <TreeView Name="Document_TreeView" ItemsSource="{Binding Source={StaticResource DocumentCVS}, Path=Groups}" Margin="5"
              ItemTemplate="{StaticResource level1Template}"                   SelectedItemChanged="Document_TreeView_SelectedItemChanged"
              >

    </TreeView>

</DockPanel>

代码背后:

using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Threading;

namespace WpfApplication4
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow2 : Window
    {
        public MainWindow2()
        {
            InitializeComponent();
        }

        private void Expand_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (object item in Document_TreeView.Items)
            {
                TreeViewItem treeItem = Document_TreeView.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
                treeItem.IsExpanded = true;
                DoEvents();
                if (treeItem != null) ToggleChild(treeItem, true);
            }
        }

        private void Collapse_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (object item in Document_TreeView.Items)
            {
                 TreeViewItem treeItem = Document_TreeView.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
                treeItem.IsExpanded = false;
                DoEvents();
                if (treeItem != null) ToggleChild(treeItem, false);
            }
        }

        private void Invert_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (object item in Document_TreeView.Items)
            {
                TreeViewItem treeItem = Document_TreeView.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;

                bool isCurrentlyExpanded = treeItem.IsExpanded;

                treeItem.IsExpanded = !isCurrentlyExpanded;
                DoEvents();
                if (treeItem != null) ToggleChild(treeItem, !isCurrentlyExpanded);
            }
        }

        private void Document_TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            ItemsControl selected = Document_TreeView.ItemContainerGenerator.ContainerFromItem(Document_TreeView.SelectedItem) as ItemsControl;
            ToggleChild(selected, true);
        }

        private void ToggleChild(ItemsControl items, bool expand)
        {
            foreach (object obj in items.Items)
            {
                ItemsControl childControl = items.ItemContainerGenerator.ContainerFromItem(obj) as ItemsControl;
                if (childControl != null)
                {
                    ToggleChild(childControl, expand);
                }
                TreeViewItem item = childControl as TreeViewItem;
                if (item != null) item.IsExpanded = true;
            }
        }

        private delegate void EmptyDelegate();

        public static void DoEvents()
        {
            Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new EmptyDelegate(delegate { }));
        }
    }
}

正如您所看到的,我有所有节点的自动扩展/折叠工作,但我似乎无法找到一种方法来单击节点并向下扩展并选择第一个子节点 . 当我调用相同的ToggleChild()方法时,生成的ItemsControl为null . 我究竟做错了什么?