简体   繁体   中英

Display multiple TreeViews as an ObservableCollection of List of TreeViewItems in WPF

Since I can only ask one question per post, I will try again here.

I try to explain my problem as simple as I can. I would like to load a KML file and show its structure as a TreeView. The asynchronous load method populates the whole TreeView with root nodes and children nodes.

It works fine if I only load 1 KML file. But I would like to load multiple KML files and show the whole structure as a list of TreeViews if possible.

My View.xaml looks like that:

<ListView ItemsSource="{Binding TreeViews}">
            <ListView.ItemTemplate>
                <HierarchicalDataTemplate>
                    <TreeView Name="TreeView" MaxHeight="300" SelectedItemChanged="TreeView_SelectedItemChanged" ItemsSource="{Binding TreeViewItems}">
                        <TreeView.ItemContainerStyle>
                            <Style TargetType="{x:Type TreeViewItem}">
                                <Setter Property="IsExpanded" Value="True"/>
                            </Style>
                        </TreeView.ItemContainerStyle>
                        <TreeView.ItemTemplate>
                            <HierarchicalDataTemplate DataType="{x:Type local:TreeViewItem}" ItemsSource="{Binding ChildrenItems}">
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox Focusable="False" IsChecked="{Binding IsChecked}"/>
                                    <ContentPresenter Margin="2,0,0,0" Content="{Binding NodeName, Mode=OneTime}"/>
                                </StackPanel>
                            </HierarchicalDataTemplate>
                        </TreeView.ItemTemplate>
                    </TreeView>
                </HierarchicalDataTemplate>
            </ListView.ItemTemplate>
</ListView>

In my ViewModel I have two properties:

public ObservableCollection<List<TreeViewItem>> TreeViews { get; set; }

private List<TreeViewItem> treeViewItems;
public List<TreeViewItem> TreeViewItems
{
    get { return treeViewItems; }
    set
    {
        treeViewItems = value;
        OnPropertyChanged();
    }
}

For testing purposes I just added a few items in the load method:

List<TreeViewItem>  temp = new List<TreeViewItem>();

TreeViewItem rootItem = new TreeViewItem(null, null);
TreeViewItem ChildItem1 = new TreeViewItem(null, null);
TreeViewItem ChildItem2 = new TreeViewItem(null, null);

rootItem.ChildrenItems.Add(ChildItem1);
rootItem.ChildrenItems.Add(ChildItem2);

temp.Add(rootItem);

TreeViewItems = temp;

TreeViews.Add(TreeViewItems);
TreeViews.Add(TreeViewItems);

Now it should show 2 identical TreeViews in the View. But unfortunately it only shows 2 empty list items with a CheckBox.

Does anybody have a hint for me how I can show multiple TreeViews?

Your question doesn't make much sense at present - why do you think you need TreeViews within TreeViews to handle this hierarchical data structure? What is local:TreeViewItem and how is it different to System.Windows.Controls.TreeViewItem ?

You'd be much better off separating out the data structure from the visual controls. Something like this, with distinct classes for each level of items to be displayed in the TreeView.

public class KLMFile
{
    public string FileName {get; set;}
    ...
    public List<KLMItem> Children {get;} = new List<KLMItem>();
}

public class KLMItem
{
    public string Description {get;set;}
    ...
    public List<KLMSubItem> Children {get;} = new List<KLMSubItem>();  
}

public class KLMSubItem
{
    public string Description {get;set;}
    ...
    // top level items - no children
} 

Assign (or bind) a collection of KLMFile items as the ItemsSource property of your TreeView control.

Create a HierarchicalDataTemplate (or plain DataTemplate for the highest level items that don't have more children) for each item type within the TreeView.

<TreeView ItemsSource="{Binding KLMFileList}">
    <TreeView.Resources>
        <HierarchicalDataTemplate
            DataType="{x:Type local:KLMFile}"
            ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding FileName}" />
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate
            DataType="{x:Type local:KLMItem}"
            ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Description}" />
        </HierarchicalDataTemplate>

        <DataTemplate
            DataType="{x:Type local:KLMSubItem}">
            <TextBlock Text="{Binding Description}" />
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

More details on WPF TreeViews (but focussing more on using them within the MVVM design pattern) on my blog post .

The ListView is bound to an ObservableCollection<List<TreeViewItem>> but you are trying to bind to a non-existing TreeViewItems property of the List<TreeViewItem> in your ItemTemplate :

<TreeView Name="TreeView" MaxHeight="300" ItemsSource="{Binding TreeViewItems}">

This won't work. You should bind directly to the List<TreeViewItem> :

<TreeView Name="TreeView" MaxHeight="300" ItemsSource="{Binding}">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM