0

Given following model

class Storage
{
    public List<Stored> StoredItems { get; }
}

class Stored
{
    public string Name { get; set; }
    public List<File> Files { get; } = new List<File>();
}

class File
{
    public string Name { get; set; }
    public Tree Schema { get; set; }
}

class Tree
{
    public string Label { get; set; }
    public List<Tree> Children { get; set; } = new List<Tree>();
}

I would like to display Storage in TreeView as follows:

StoredItem1.Name
  File1.Schema.Label
    File1.Schema.Children[0].Label
    File1.Schema.Children[1].Label
      File1.Schema.Children[1].Children.Label
  File2.Schema.Label
StoredItem2.Name

i.e. display all Storeds that would contain Schema of each file, which is recursive.

I am not sure how to achieve it, my main problem is how to get the Schema to be displayed. When I changed my model to wrap Schema in a singleton list, it started to work but I would like to avoid polluting my model with such thing, also still, I don't want to display file name and instead of file display its schema.

Another thing I would like to have have a property SelectedStoredItem in my view model and bind it to, well, selected Stored item. It can be null if for example some schema node is selected, or be equal to the Stored to which selected node belongs, but I prefer first option.

Here is my xaml, it doesn't do what I want, just displays Stored items and their file names.

<Window x:Class="TreeViewTest.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:TreeViewTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Storage/>
    </Window.DataContext>
    <Grid>
        <TreeView
                ItemsSource="{Binding StoredItems}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:Stored}"
                                          ItemsSource="{Binding Files}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:File}"
                                          ItemsSource="{Binding Schema}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Tree}"
                                          ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Label}"/>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

and here is complete code behind

namespace TreeViewTest
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    class Storage
    {
        public Storage()
        {
            StoredItems = new List<Stored>();
            var a1 = new Stored {Name = "Stored1"};
            a1.Files.Add(new File
            {
                Name = "File1",
                Schema = new Tree
                {
                    Label = "1_1",
                    Children = new List<Tree> { new Tree { Label = "1_1_1" } }
                }
            });
            a1.Files.Add(new File
            {
                Name = "File2",
                Schema = new Tree
                {
                    Label = "2_1",
                    Children = new List<Tree> { new Tree { Label = "2_1_1" }, new Tree { Label = "2_1_2" } }
                }
            });

            var a2 = new Stored { Name = "Stored2" };
            a2.Files.Add(new File
            {
                Name = "File1",
                Schema = new Tree
                {
                    Label = "1_1",
                    Children = new List<Tree> { new Tree { Label = "1_1_1" } }
                }
            });

            StoredItems.Add(a1);
            StoredItems.Add(a2);
        }

        public List<Stored> StoredItems { get; }
    }

    class Stored
    {
        public string Name { get; set; }
        public List<File> Files { get; } = new List<File>();
    }

    class File
    {
        public string Name { get; set; }
        public Tree Schema { get; set; }
    }

    class Tree
    {
        public string Label { get; set; }
        public List<Tree> Children { get; set; } = new List<Tree>();
    }
}

1 Answer 1

1

I don't want to display file name and instead of file display its schema

so change data template for file

<HierarchicalDataTemplate DataType="{x:Type local:File}"
                          ItemsSource="{Binding Schema.Children}">
    <TextBlock Text="{Binding Schema.Label}"/>
</HierarchicalDataTemplate>

side note

Children = new List<Tree> { new Tree { Label = "2_1_1" }, new Tree { Label = "2_1_2" } }

creating a new List inside object initializer is not necessary here. It has already been initialized (public List<Tree> Children { get; set; } = new List<Tree>();) and you can write a like this:

Children = { new Tree { Label = "2_1_1" }, new Tree { Label = "2_1_2" } }
Sign up to request clarification or add additional context in comments.

1 Comment

Damn, this was pretty simple. Regarding the initialization, I initialized list for every object just to be sure that I don't get a null, I don't do this kind of things in real code, just wanted to put up the structure quickly. Still nice too know this syntax sugar. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.