Search code examples
c#wpfgroupingone-to-manycollectionviewsource

CollectionViewSource grouping one item to multiple groups


I am trying to mimic the msn messenger contactlist treeview display. I have a Contact object which has a Groups property that returns an array msngroups that the Contact belongs, this meaning say I have something as per bellow

Class Contact
{
    string Name;
    string[] Groups {get;set;}
 }

 ObservableCollection<Contact> ContactList;

So a contact can be in mutiple groups, is that possible to use CollectionViewSource to generate the correct view to feed a wpf TreeView?


Solution

  • The grouping would work when you flatten this hierarchy i.e. "Contact having Groups" into "Repeated Contacts having each single group" ...

    e.g.

    If you have 4 items with groups like ...

    Dog { mammal, quadruped }
    Man { mammal, biped }
    PrayingMantis { insect, quadruped }
    Pegion { bird, biped }
    

    Then you new flat list should be like this...

    <mammal, Dog>
    <mammal, Man>
    <bird, Pigeon> 
    <insect, PrayingMantis>
    <biped, Man>
    <biped, Pigeon>
    <quadruped, Dog>
    <quadruped, PrayingMantis>
    

    So after applyin grouping on the Keys above it should be

    mammal { Dog, Man }
    bird { Pigeon }
    insect { PrayingMantis }
    biped { Man,  Pigeon }
    quadruped { Dog, PrayingMantis }
    

    C# Code:

    //Flatten the groups into a KeyValuePair<string, Contacts> list using LINQ.
    var flatGroups 
        = listGroups.SelectMany(
            ctc => ctc.Groups.Select(
                 grp => new KeyValuePair<string, Contact>(grp, ctc))).ToList();          
    
    //Apply CollectionViewSource group on the `Key`.
    var collectionVwSrc = new CollectionViewSource();
    collectionVwSrc.Source = flatGroups;
    collectionVwSrc.GroupDescriptions.Add(new PropertyGroupDescription("Key"));
    
    //Apply groups as itemssource to the TreeView.
    MyGroupsTree.ItemsSource = collectionVwSrc.View.Groups; 
    

    XAML

        <TreeView x:Name="MyGroupsTree">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                    <!--GroupItem.Name--> 
                    <TextBlock Text="{Binding Path=Name}" 
                               FontWeight="Bold"/>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <!--Contact.Name-->
                            <TextBlock Text="{Binding Value.Name}"/>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    

    Let me know if this helps...