I disagree with itowlson here. This isn't a hairy problem and HierarchicalDataTemplate
was made for this kind of thing. Before you go haphazardly diving into patterns and view-models and other unnecessary obfuscation, consider that your problem can be solved with two classes and a single Linq GroupBy
statement.
Here are your classes:
public class GroupItem
{
public string Name
{
get;
private set;
}
public string Group
{
get;
private set;
}
public GroupItem(string name, string group)
{
Name = name;
Group = group;
}
}
public class Group
{
public IEnumerable<GroupItem> Children
{
get;
set;
}
public string Name
{
get;
private set;
}
public Group(string name)
{
Name = name;
}
}
So far, so good. You've got two straightforward classes to hold all the necessary data. Names and Groups are stored as strings. A Group
has a collection of GroupItem
. Now for the code in your Window
:
public partial class DistinctLeaves : Window
{
public ObservableCollection<GroupItem> Items
{
get;
set;
}
public IEnumerable<Group> Groups
{
get;
set;
}
public DistinctLeaves()
{
Items = new ObservableCollection<GroupItem>();
Items.Add(new GroupItem("Item A", "Group A"));
Items.Add(new GroupItem("Item B", "Group A"));
Items.Add(new GroupItem("Item C", "Group B"));
Items.Add(new GroupItem("Item D", "Group C"));
Groups = Items.
GroupBy(i => i.Group).
Select(g => new Group(g.Key) { Children = g });
InitializeComponent();
}
}
Once again, this is all boilerplate except the group-by line. That statement merits further investigation. This will group your items collection according to their Group
property. After the items are in groups, you then create a new instance of the Group
class. Pass in the group's name property (which is the key), and set the children to the group itself, and ta-da!
Finally, here is the XAML for the Window
, which uses the HierarchicalDataTemplate
:
<Window x:Class="TestWpfApplication.DistinctLeaves"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DistinctLeaves" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TreeView ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
And here is the result: