【问题标题】:C# WPF TreeView HierarchicalDataTemplate - Echo parent node text at the end of the listC# WPF TreeView HierarchicalDataTemplate - 在列表末尾回显父节点文本
【发布时间】:2016-01-08 21:13:19
【问题描述】:

我正在寻找一种使用 TreeView(WPF,c#)在元素列表末尾回显父节点名称的方法。

我正在处理的信息列表可能很长,我想向用户展示他们所在的“类别”,而不必向上滚动到列表顶部。我有一个 HierarchicalDataTemplate 可以进行一些简单的字体格式设置,但我看不到“关闭”节点的放置位置,或者如何获取它的文本。

这是我正在尝试做的一个简化示例:

【问题讨论】:

    标签: c# wpf xaml treeview hierarchicaldatatemplate


    【解决方案1】:

    您至少可以通过两种方式做到这一点。第一种方法是重新定义整个树视图样式。您可以找到一些示例如何做到这一点here(该示例不能解决您的问题,但您可以大致了解)。这个解决方案的缺点是代码非常大,而且在每个系统上看起来都一样,比如 Windows 10 的 Windows XP,因为在正常情况下每个系统都使用自己的样式。

    我更喜欢以另一种方式解决此类问题。我从 C# 代码进行更改。例如,在你的情况下,你可以在 Visual Studio Xaml 可视化器中看到 treeview 的结构:

    每个树视图项都包含一个切换按钮 - 用于在网格的第一行展开和折叠。接下来是一个包含带有项目内容的 TextBlock 的边框(在您的情况下,它可以是您的数据模板中的另一个控件,我以 textblock 为例)。它放在同一个第一行。在网格的第二行有 ItemsPresenter 包含子元素。

    所以,我们的目标是在网格的第二行再添加一行,并在那里放置一个文本块。

    首先,将 ItemContainerStyle 添加到树视图并在那里设置事件处理程序:

    <TreeView.ItemContainerStyle>
      <Style TargetType="{x:Type TreeViewItem}">
        <EventSetter Event="Loaded" Handler="Item_Loaded"/>
      </Style>
    </TreeView.ItemContainerStyle>
    

    然后在后面的代码中:

    void Item_Loaded(object sender, RoutedEventArgs e) {
        // Find the main grid of this TreeView item.
        Grid grid = FindVisualChild<Grid>((DependencyObject) sender);
    
        // Add new row, because it has only 2 and we need 3
        grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
    
        // Get the content to put into the textblock (or another control you are using in datatemplate)
        string text = ((Node) grid.DataContext).Name;
    
        // I'm using TextBlock to show example, you can use your own control
        TextBlock tb = new TextBlock {
            Text = text,
            Foreground = new SolidColorBrush(Colors.Gray),
        };
    
        grid.Children.Add(tb);
    
        // Visibility of our modification depends on IsExpanded and amount of child elements. If itemcontainer is collapsed or doesn't have children, we don't show this modification.
        bool flag = false;
        grid.SizeChanged += (sender1, e1) => {
            if (flag) {
                return;
            }
            flag = true;
            tb.Visibility = grid.RowDefinitions[1].ActualHeight > 0
            ? Visibility.Visible
            : Visibility.Collapsed;
            flag = false;
        };
    
        // Set the position of the added part
        tb.SetValue(Grid.RowProperty, 2);
        tb.SetValue(Grid.ColumnProperty, 1);
    }
    

    这不是理想的解决方案,Xaml 在不同的系统上可能会有所不同,因此此功能可能会略有不同。我只在 Windows 10 上检查过。

    FindVisualChild 函数是这样的:

    static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject {
        for (int i = 0 ; i < VisualTreeHelper.GetChildrenCount(obj) ; i++) {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child is T) {
                return (T) child;
            }
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null) {
                return childOfChild;
            }
        }
        return null;
    }
    

    【讨论】:

    • 感谢您的详细回复。我采用了您建议的方法背后的代码,并且效果很好。
    【解决方案2】:

    我实际上会采用不同的方法。实际上有一些。

    首先是简单地为父节点重新模板化 TreeViewItem。考虑到它的“肉”只是一个带有披露切换的网格,一个用于标题的 ContentPresenter(这是树中的“项目”)和一个 ItemsControl(它的 ItemsSource 绑定到节点的子节点),这很好而且很容易嵌套更多这些容器。只需在模板的网格中添加第三行,插入另一个内容演示者并将其绑定也设置为标题,您就完成了。你可以用简单的风格做到这一点。根本不需要代码隐藏。

    您可以做的第二件事是添加一个完全独立的“crumbtrail”控件以在关联树。他们真的很容易做到。在树中选择项目时,沿着层次结构向上走,将项目添加到 List,然后将其绑定到 ListBox,并为其 ItemsPanel 提供水平堆栈面板。当然,您需要对其进行一些模板化以添加分隔符等,但它也为您提供了一个“可点击”的线索。

    无论如何,这只是两个想法。也许他们甚至可以激发第三个人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-22
      • 1970-01-01
      • 2015-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多