-1

I am writing an application for teachers and students in which a teacher can lookup grades of his students based on a selected subject.

In order to group everything together I have created a dictionary which contains all grades of students in a selected subject (e.g. all grades from Math, it doesn't really matter here):

IDictionary<Class, List<KeyValuePair<Student, List<Grade>>>>

Class is a key to this dictionary which is just a class that students belong to. It has a name of type string that I would like to display (e.g. "4F")

Value is a list that contains a Students from given class and a list of his/her Grades (every Grade has Value and Description, e.g. 3- and "Algebra exam", I would like to display them too).

Basically what I would like to see for every Class (which means for every Key in a dictionary) is something like this (number of students and grades may vary):

  • ClassName
    • Student
      • Grade - Description
    • Student2
      • Grade - Description
      • Grade2 - Description

I've been looking for a solution, I think it might involve using <TreeView.Resources> and <HierarchicalDataTemplate> but to be honest I don't really understand how to use them. I tried one solution and displayed only every ClassName and Students that are connected with a class, but couldn't display anything else. Another solution suggested here: Simple Nested TreeView Xaml structure? left me with:

[SchoolerDatabaseUtilities.Class,System.Collections.Generic.List'1[System.Collections.Generic.KeyValuePair'2[SchoolerDatabaseUtilities.Student,System.Collections.Generic.List'1[SchoolerDatabaseUtilities.Grade]]]] 

written for every Key that I had in a dictionary (SchoolerDatabaseUtilities is just a library that I use in order to keep everything in my files clean).

Please help me with anything because I don't even know where to start...

It was suggested that my question was a duplicate of WPF TreeView hierarchical binding. but to me it doesn't seem like it. I was using Dictionary, not a List<>() and it seems to me that my problem was slightly harder in it's nature (whether my approach to a problem was good in terms or readability or not).

kazulla
  • 55
  • 2
  • 9
  • Though the `Dictionary` is useful for behind the scenes, when it comes to a ViewModel you probably want to copy the items into an `ObservableCollection`. Then I would have thought the solution in the link you provided straight-forward? –  Sep 02 '19 at 00:24
  • Possible duplicate of [WPF TreeView hierarchical binding.](https://stackoverflow.com/questions/12532435/wpf-treeview-hierarchical-binding) –  Sep 02 '19 at 06:40

2 Answers2

1

You will have.to use the HierarchicalDataTemplate.

But you should try to rework your design and build your types to explicitly reflect the tree data structure - without nested collections. This means Class should have a child collection of type Student and Student a child collection of type Grade. Then Class or a collection of Class would become the root of your tree (the ItemsSource binding source of the whole TreeView). If you would have done this, then the templates could have the DataType property set, which would make all the type casts redundant. It's also much more convenient to work with and improves readability.

<TreeView ItemsSource="{Binding TreeSource}">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Value}">
      <TextBlock Text="{Binding Key.(Class.Name)}" />

      <HierarchicalDataTemplate.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Value}">
          <TextBlock Text="{Binding Key.(Student.Name)}" />

          <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate DataType="Grade">
              <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Value}" />
                <TextBlock Text="{Binding Description}" />
              </StackPanel>
            </DataTemplate>
          </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
      </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>
</TreeView>
BionicCode
  • 1
  • 4
  • 28
  • 44
  • I followed your advice and redesigned how I am storing all information and after some tweaking in my XAML I got it working. Thanks! – kazulla Sep 02 '19 at 12:55
1

I followed BionicCode's advice and Microsoft Docs and made List<Class> where every Class has List<Student> and every Student has List<Grade> which made everything better and easier.
After all my code looks like this:

<TreeView ItemsSource="{Binding MyListOfClasses}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type utilities:Class}" ItemsSource="{Binding StudentList}">
               <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type utilities:Student}" ItemsSource="{Binding GradesList}">
               <TextBlock Text="{Binding FullNameRev}" />
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type utilities:Grade}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="75" />
                    <ColumnDefinition Width="500" />
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Value}" Grid.Column="0"/>
                <TextBlock Text="{Binding Description}" Grid.Column="1"/>

            </Grid>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

where utilities is defined in my <UserControl> tag as a:

xmlns:utilities="clr-namespace:SchoolerDatabaseUtilities;assembly=SchoolerDatabaseUtilities"

And SchoolerDatabaseUtilities is my library with definition of all of these classes

kazulla
  • 55
  • 2
  • 9