wpfxamllistviewcollectionviewexpander

ListView grouping using multiple collections and custom headers


I have three collections like so:

IReadOnlyList<Info> ListA = {'1A', '1B'}
IReadOnlyList<Info> ListB = {'2A', '2B'}
IReadOnlyList<Info> ListC = {'3A', '3B'}

I am trying to group them, add a custom header to each and show then in a ListView. I tried doing this:

<ListView ItemsSource="{DynamicResource FullCollection}">
          <ListView.Resources>
            <CollectionViewSource x:Key="CollectionA" Source="{Binding CollectionA}" />
            <CollectionViewSource x:Key="CollectionB" Source="{Binding CollectionB}" />
            <CollectionViewSource x:Key="CollectionC" Source="{Binding CollectionC}" />
            <CompositeCollection x:Key="FullCollection">
              <ListViewItem IsEnabled="False">Header_A</ListViewItem>
              <CollectionContainer Collection="{Binding Source={StaticResource CollectionA}}" />
              <ListViewItem IsEnabled="False">Header_B</ListViewItem>
              <CollectionContainer Collection="{Binding Source={StaticResource CollectionB}}" />
              <ListViewItem IsEnabled="False">Header_C</ListViewItem>
              <CollectionContainer Collection="{Binding Source={StaticResource CollectionC}}" />
            </CompositeCollection>
          </ListView.Resources>
</ListView>
...

Then i created three seperate ICollectionView objects in viewmodel (CollectionA, CollectionB, CollectionC from ListA, ListB, ListC recpectively) like so:

 ICollectionView _collectionA= null;
 public ICollectionView CollectionA  //from ListA
    {
      get
      {
        if (_collectionA== null)
        {
          _collectionA = CollectionViewSource.GetDefaultView(ListA);  //original list
          PropertyGroupDescription groupDescription = new PropertyGroupDescription("Header_A");
          _collectionA.GroupDescriptions.Add(groupDescription);
        }
        return _collectionA;
      }
    }
...

Somehow i am not able to get what I want , what am i doing wrong here!?

How can i group them with custom headers (& expanders) and show then in my ListView, like this:

  ^ Header_A
       --1A
       --1B
   ^ Header_B
       --2A
       --2B
   ^ Header_C
       --3A
       --3B

Solution

  • You should create a view model with an additional property for the group header:

    public class InfoViewModel
    {
        public string Category { get; set; }
        public string Name { get; set; }
    }
    

    You would then translate your current Info objects to InfoViewModels and group by the new property, e.g.:

    var fullSourceCollection = ListA.Select(x => new InfoViewModel() { Category = "Header_A", Name = x.Name })
        .Merge(ListB.Select(x => new InfoViewModel() { Category = "Header_B", Name = x.Name })
        .Merge(ListC.Select(x => new InfoViewModel() { Category = "Header_C", Name = x.Name })
        .ToArray();
    ...
    PropertyGroupDescription groupDescription = new PropertyGroupDescription(nameof(InfoViewModel.Category));
    ...
    

    Finally, you should define a group style in the view:

    <ListView ...>
        <ListView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Name}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ListView.GroupStyle>
    </ListView>