Grouping child objects in WPF TreeView
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')
- Object Group #1
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
- Type A
- Object Group #1
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 TreeVi开发者_JS百科ew 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.
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.
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>
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
.
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}"
... />
精彩评论