WPF如何将一个TreeView绑定到另一个TreeView?

3
我正在尝试将TreeView t2绑定到xaml中的TreeView t1,代码如下:
<Window x:Class="WpfApp2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp2"
    mc:Ignorable="d"
    Title="MainWindow" Height="620" Width="600">
<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type TreeViewItem}" ItemsSource="{Binding Items}">
        <StackPanel Orientation="Horizontal" >
            <TextBlock Background="AliceBlue" Text="{Binding Path=Header, Mode=TwoWay}" Width="220"/>
        </StackPanel>
    </HierarchicalDataTemplate>
</Window.Resources>
<StackPanel>
    <TreeView x:Name="t1">
        <TreeView.Items>
            <TreeViewItem Header="a"></TreeViewItem>
            <TreeViewItem Header="b"></TreeViewItem>
        </TreeView.Items>
    </TreeView>
    <TreeView x:Name="t2" ItemsSource="{Binding Items, ElementName=t1}"></TreeView>
</StackPanel>

我希望t2t1有相同数量的节点。但结果是,t1的所有节点都被删除了。为什么

我期望的结果:

enter image description here

实际结果:

enter image description here


我认为问题在于你无法将两个控件都作为TreeView绑定。但是你可以将一个TreeView项绑定到另一个TreeView项。 - jdweng
1
该元素只能有一个父级。绑定将一对一地复制TreeViewItems到第二个,替换父级... 我想。 - Sinatr
1
为什么不为两个控件使用同一个 ViewModel 实例? - Burim Hajrizaj
@Sinatr,看来你是对的,但我不明白为什么ItemsSource要这样实现? - ricky
1
@BurimHajrizaj 是的,我可以使用 ViewModel 的方式,但我只是想了解为什么我不能这样做。 - ricky
2个回答

1

为了回答我自己的问题:

从源代码中找到了答案。看起来这是经过设计的(我仍然不明白为什么要这样设计)。如果给出的项目是TreeViewItem,那么它将被用作节点容器,而不是创建一个新的容器。

ItemsControl.cs(第1323行)

/// <summary>
    /// Return the element used to display the given item
    /// </summary>
    DependencyObject IGeneratorHost.GetContainerForItem(object item)
    {
        DependencyObject container;

        // use the item directly, if possible (bug 870672)
        if (IsItemItsOwnContainerOverride(item))
            container = item as DependencyObject;
        else
            container = GetContainerForItemOverride();

        // the container might have a parent from a previous
        // generation (bug 873118).  If so, clean it up before using it again.
        //
        // Note: This assumes the container is about to be added to a new parent,
        // according to the ItemsControl/Generator/Container pattern.
        // If someone calls the generator and doesn't add the container to
        // a visual parent, unexpected things might happen.
        Visual visual = container as Visual;
        if (visual != null)
        {
            Visual parent = VisualTreeHelper.GetParent(visual) as Visual;
            if (parent != null)
            {
                Invariant.Assert(parent is FrameworkElement, SR.Get(SRID.ItemsControl_ParentNotFrameworkElement));
                Panel p = parent as Panel;
                if (p != null && (visual is UIElement))
                {
                    p.Children.RemoveNoVerify((UIElement)visual);
                }
                else
                {
                    ((FrameworkElement)parent).TemplateChild = null;
                }
            }
        }

        return container;
    }

并且 树形视图 (第400行)

public class TreeView : ItemsControl {
    ...
    /// <summary>
    ///     Returns true if the item is or should be its own container.
    /// </summary>
    /// <param name="item">The item to test.</param>
    /// <returns>true if its type matches the container type.</returns>
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is TreeViewItem;
    }
    ....
}

1
我期望 t2t1 拥有相同数量的节点。但结果是,所有的 t1 节点都被删除了。为什么?
因为诸如 TreeViewItem 等可视元素的实例只能在可视树中出现一次。一个元素最多只能有一个可视父级,在这种情况下,项目将从第一个 TreeView 中删除并添加到第二个 TreeView 中。
因此,您需要克隆每个要在两个 TreeViews 中显示的 TreeViewItem 元素。

如果我绑定到一个ViewModel对象,它将根据HierarchicalDataTemplate创建TreeViewItem。但是当绑定到t1.Items时为什么会有所不同? - ricky
因为每个ItemsSource中的项都会创建一个TreeViewItem容器。在您的示例中,您明确创建了两个TreeViewItem元素。还要注意,HierarchicalDataTemplate的DataType不应该是TreeViewItem,而应该是您的数据对象类型。您不应该明确创建任何TreeViewItem元素。 - mm8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接