Question

I have a set of data that is structured like this:

 ItemA.GroupA
 ItemB.GroupA
 ItemC.GroupB
 ItemD.GroupC

I need to present the data in a WPF Tree View like this:

GroupA

--- ItemA

--- ItemB

GroupB

--- ItemC

GroupC

--- ItemD

What XAML can I use to group the leaves by distinct value? For instance, there could be multple items in the collection which are GroupA.ItemA, however, I only want to present the node and leaf once.

Was it helpful?

Solution

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:

alt text http://img339.imageshack.us/img339/8555/distinctleaves.jpg

OTHER TIPS

You're not going to be able to do that in XAML, at least not in any natural way. A better approach is to introduce a view model -- a class that represents your data in a view-friendly manner so that you can keep your XAML simple and natural.

Thus, in your case, you would have a class that wraps your ItemX collection, and exposes the groups and their distinct members:

public class MyItemsViewModel
{
  public IList<MyGroupViewModel> Groups { get; }
}

public class MyGroupViewModel
{
  public string GroupName { get; }
  public IList<MyItem> DistinctItems { get; }
}

Your HierarchicalDataTemplate will then fall out almost automatically. As a further benefit, because your view model classes are just data objects, you can put them under automated test, whereas complex XAML requires manual testing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top