Как реализовать кастомную группировку в 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
в надежде, что это поможет, однако столкнулся с проблемами:
- Заголовок группы не отображается.
- Если несколько объектов относятся к одной группе, то отображается только первый.
Что я делаю не так? Буду признателен за любую помощь.