Как реализовать кастомную группировку в ListBox?

Есть ли возможность реализовать "кастомную" группировку для ListBox без использования CollectionView и CollectionViewSource?

У меня есть простая реализация MVVM с коллекцией, в которую загружаются сгруппированные объекты. Также для работы с коллекциями использовал DynamicData.

Ниже приведён весь код приложения.

ChatMessage.cs:

public class ChatMessage
{
    public long Id { get; set; }
    public long Sender { get; set; }
    public long Receiver { get; set; }
    public string Content { get; set; }
    public DateTime Timestamp { get; set; }
    public bool Read { get; set; }
    public bool Delivered { get; set; }
}

MainWindow.xaml:

<Window
    x:Class="DynamicDataTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:DynamicDataTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">

    <Window.DataContext>
        <local:ChatViewModel />
    </Window.DataContext>
    <Grid>
        <ListBox ItemsSource="{Binding GroupedMessages}">
            <ListBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock
                                Margin="0,10,0,5"
                                FontSize="14"
                                FontWeight="Bold"
                                Text="{Binding Key, StringFormat={}{0:dd MMMM yyyy}}" />
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ListBox.GroupStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Margin="20,0,0,0" Text="{Binding Content}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

ChatViewModel.cs:

public class ChatViewModel : AbstractNotifyPropertyChanged
{
    private readonly SourceCache<ChatMessage, long> _sourceList = new SourceCache<ChatMessage, long>(m => m.Id);

    public ObservableCollectionExtended<GroupAdapter> GroupedMessages { get; }

    public ChatViewModel()
    {
        // Load test messages
        GetTestMessages();  

        _sourceList
            .Connect()
            .Group(msg => msg.Timestamp.Date)
            .Transform(group => new GroupAdapter(group))
            .Bind(GroupedMessages)
            .Subscribe();
    }

    private void GetTestMessages()
    {
        var messages = new[]
        {
            new ChatMessage { Id = 1, Sender = 1, Receiver = 2, Content = "Hi!", Timestamp = DateTime.Now.AddDays(-1) },
            new ChatMessage { Id = 2, Sender = 2, Receiver = 1, Content = "Hi, how are you ?", Timestamp = DateTime.Now.AddDays(-3).AddHours(1) },
            new ChatMessage { Id = 3, Sender = 1, Receiver = 2, Content = "I'm fine!", Timestamp = DateTime.Now },
            new ChatMessage { Id = 4, Sender = 2, Receiver = 1, Content = "Nice!", Timestamp = DateTime.Now },
        };

        foreach (var message in messages)
            _sourceList.AddOrUpdate(message);
    }
}

GroupAdapter.cs:

public class GroupAdapter : IGrouping<DateTime, ChatMessage>
{
    private readonly IGroup<ChatMessage, long, DateTime> _group;

    public GroupAdapter(IGroup<ChatMessage, long, DateTime> group)
    {
        _group = group;
    }

    public DateTime Key => _group.Key;

    public IEnumerator<ChatMessage> GetEnumerator() => _group.Cache.Items.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

В связи с проблемой утечки памяти при использовании CollectionView возник вопрос:

Есть ли возможность реализовать "кастомную" группировку для ListBox?

Как видно выше, я реализовал интерфейс IGrouping в GroupAdapter в надежде, что это поможет, однако столкнулся с проблемами:

  1. Заголовок группы не отображается.
  2. Если несколько объектов относятся к одной группе, то отображается только первый.

Результат работы

Что я делаю не так? Буду признателен за любую помощь.


Ответы (0 шт):