Grouping child objects in WPF TreeView
Asked Answered
C

4

8

I am trying to get my tree view to group a collection of similar items by what they are. To keep things generic, my object hierarchy could look like this:

  • Objects
    • Object Group #1
      • Item #1 (Type 'A')
      • Item #2 (Type 'A')
      • Item #3 (Type 'B')
      • Item #4 (Type 'B')

Right now my TreeView shows these objects exactly like the object model, but what I would like to do is insert a TreeView node for each object type so that it would look like this:

  • Objects
    • Object Group #1
      • Type A
        • Item #1
        • Item #2
      • Type B
        • Item #3
        • Item #4

I saw in a similar question here that someone recommended to have two separate HierarchicalDataTemplates so I created one for 'Object Group #1' level which contains a TreeView with a list of the types, but this is really clumsy since it is a whole separate TreeView inside of some nodes. I have also been trying to use a CollectionViewSource to filter out the items in each category, but this doesn't do me very much good since I can't figure out how to display them.

I guess my question boils down to this: How do I make a HierarchicalDataTemplate group it's children? If someone could point me in the right direction I would appreciate it a lot.

I can post some code if anyone wants to see, but I am really just trying to figure out how to do what I want so my code is just a pretty straight forward databound treeview right now.

Carrico answered 11/2, 2010 at 22:41 Comment(0)
B
7

Take a look at this article by Mr. Sumi. I'm sure it will help you.

The gist of the article:

My solution to that very problem requires the following ingredients:

  • A MultiBinding that allows you to combine different bindings.
  • A converter that helps us organizing the different bound collections into sub folders, where necessary.
  • And of course: Data templates that provide a visual representation of your bound data.
Bathulda answered 12/2, 2010 at 10:3 Comment(0)
F
7

You can achieve this effect by binding the ItemsSource on your HierarchicalDataTempalate using an IValueConverter. This converter is simply does the following:

public class MyConverter : IValueConverter
{
  public object Convert(object value, ...)
  {
    return
      from item in (IEnumerable<MyItem>)value
      group item by item.Type into g
      select new { Type = g.Key, Items = g }
  }
  ...
}

Now your HierarchcialDataTemplate can be as follows:

<HierarchicalDataTemplate ItemsSource="{Binding SomePath, Converter={x:Static local:MyConverter}">

  <HierarchicalDataTemplate.ItemTemplate>
    <HierarchicalDataTemplate
      ItemsSource="{Binding Items}"
      TargetType="{x:Type local:MyItem}"

      ItemTemplate="{StaticResource MyItemTemplate}">
         <!-- may omit ItemTemplate in prior line to use implicit template -->

      <TextBlock Text="{Binding Type}" /> <!-- Header for type -->

    </HierarchicalDataTemplate>
  </HierarchicalDataTemplate.ItemTemplate>

  <!-- header for "Object Group #1" -->

</HierarchicalDataTemplate>
Fieldsman answered 12/2, 2010 at 10:55 Comment(2)
select new { Type = item.Type, Items = g }; doesn't compile; maybe select new { Type = g.First().Type, Items = g };?Breastpin
Would a collection view source be more appropriate?Overtly
E
0

AFAIK, HierarchicalDataTemplate can't group its children.

View should just display whatever it gets, without really digging into objects kinds / groups... Why don't you create these groups in your object model?

And the view will just get smth like:

public interface ITreeNode
{
    string Title;
    IList<ITreeNode> ChildNodes;  
}

and display it using the HierarchicalDataTemplate.

Estrange answered 11/2, 2010 at 23:1 Comment(0)
C
0

If this is a simple Grouping Method from a Flat Collection for display purpose that you are looking for maybe using a "CollectionViewSource" will be more suitable. Using LINQ could become a nightmare due to Property/Collection Change event propagation.

<CollectionViewSource x:Key="GroupedItems" Source="{Binding ItemsSource,  ElementName=My_UserControl}">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Type" Converter="{StaticResource GroupingConverter}" />
    </CollectionViewSource.GroupDescriptions>
    <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Date"/>
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

<HierarchicalDataTemplate x:Key="GroupDataTemplate"  ItemsSource="{Binding Items}" >
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>

<TreeView x:Name="ItemHolder" x:FieldModifier="private"
    ItemsSource="{Binding Source={StaticResource GroupedItems}, Path=Groups}"
... />
Chios answered 16/6, 2015 at 0:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.