Search code examples
c#wpfxamldata-bindingtreeview

Binding multiple TreeViews to the same ItemSource


I'm trying to bind multiple TreeViews to the same ItemSource which contains TreeViewItems. Whenever I do this, the last one to load is the only one that displays the items. (So if I have three treeviews declared in a specific order, the last one declared will be the only one to display the items.)

This is a sample WPF project with default settings I created to show it:

XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView x:Name="TreeOne" ItemsSource="{Binding TreeItems}" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="238"/>
        <TreeView x:Name="TreeTwo" ItemsSource="{Binding TreeItems}" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="239" Grid.Column="1"/>
    </Grid>
</Window>

Code Behind: (I'm using MVVM in the real project but this has the same bug)

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            TreeItems = new ObservableCollection<TreeViewItem>() { new TreeViewItem() { Header = "First item" } };
            InitializeComponent();
        }

        public ObservableCollection<TreeViewItem> TreeItems { get; set; }
    }
}

picture of the output of the above code

If I comment out the second tree, the first one will display properly.


Solution

  • TreeViewItems are controls and cannot be displayed simultaneously in multiple visual trees (not the same thing as TreeView!). To fix the issue use string collection (new ObservableCollection<string> { "First item" };). In case when you have a complex data-objectsuse templating feature for their visualization, e.g:

    TreeItems = new ObservableCollection<DateTime>() 
    { 
      new DateTime(2017, 1, 1), 
      new DateTime(2017, 12, 31) 
    };
    

    xaml

    <Window.Resources>
    
        <DataTemplate x:Key="DateItem">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=Year}"/>
                <Border Background="Green" Width="2" Height="2"/>
                <TextBlock Text="{Binding Path=Month}"/>
                <Border Background="Green" Width="2" Height="2"/>
                <TextBlock Text="{Binding Path=Day}"/>
            </StackPanel>            
        </DataTemplate>
    
    </Window.Resources>
    
    <TreeView x:Name="TreeOne" ItemTemplate="{StaticResource DateItem}"/>
    <TreeView x:Name="TreeTwo" ItemTemplate="{StaticResource DateItem}"/>