Насколько я знаю, ListBox
по-прежнему останавливает виртуализацию элементов при применении групп.
Будет ли 2000 элементов работать должным образом, зависит от сложности шаблона, примененного к каждому элементу. У меня есть ListBox
с относительно простым шаблоном (около 8 TextBlock
с по горизонтали StackPanel
), и производительность начинает снижаться примерно до 1500 элементов с применением группировки. По-видимому, это также зависит от количества групп, в которые агрегируются элементы, где большее количество групп приводит к снижению производительности. Это особенно заметно при прокрутке по какой-то причине.
ListBox
делает динамическую группировку очень простой, но если вы обычно собираетесь группировать по альбомам, то, возможно, было бы лучше установить ItemsSource
вашего ItemsControl
(возможно, ListBox
) как коллекция Album
объектов, каждый из которых имеет свойство Tracks
, которое само является коллекцией Track
объектов. Предполагая это, я вижу два варианта:
- Использовать вложенные
ItemsControls
в Album
DataTemplate
- Используйте
HeaderedItemsControl
, например TreeView
с HierarchicalDataTemplate
В первом варианте вы должны управлять выбором вручную. В простейшей реализации вы могли бы иметь возможность выбирать альбомы и треки отдельно; потенциально выбранная дорожка, которая не принадлежит выбранному альбому. Возможно, вам удастся обойтись без выбора альбома, поскольку в представлении списка треков других медиаплееров, о которых я могу думать, такой концепции нет.
Решение 1 также имеет значение для навигации по клавиатуре с последнего трека одного альбома до первого трека следующего альбома.
Принимая следующий код:
public class Album
{
public string Title { get; set; }
public ObservableCollection<Track> Tracks { get; set; }
}
public class Track
{
public string Title { get; set; }
}
_tracks.ItemsSource = new[] {
new Album {
Title = "Album 1",
Tracks = new ObservableCollection<Track> {
new Track { Title = "Track 1" },
new Track { Title = "Track 2" }
}
},
new Album {
Title = "Album 2",
Tracks = new ObservableCollection<Track> {
new Track { Title = "Track 1" },
new Track { Title = "Track 2" }
}
}
};
Вот код, демонстрирующий первый вариант:
<ListBox x:Name="_tracks">
<FrameworkElement.Resources>
<DataTemplate DataType="{x:Type local:Track}">
<TextBlock Text="{Binding Path=Title}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:Album}">
<StackPanel>
<TextBlock Text="{Binding Path=Title}" />
<ListBox ItemsSource="{Binding Path=Tracks}" />
</StackPanel>
</DataTemplate>
</FrameworkElement.Resources>
</ListBox>
Измените внешний ListBox
на ItemsControl
, чтобы облегчить проблему выбора, как обсуждалось. Вы должны будете заставить это выглядеть симпатичным все же, поскольку вышеупомянутый выглядит довольно уродливым.
Второй вариант можно определить так:
<TreeView x:Name="_tracks2">
<FrameworkElement.Resources>
<DataTemplate DataType="{x:Type local:Track}">
<TextBlock Text="{Binding Path=Title}" />
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Album}"
ItemsSource="{Binding Path=Tracks}">
<TextBlock Text="{Binding Path=Title}" />
</HierarchicalDataTemplate>
</FrameworkElement.Resources>
</TreeView>
ListView
поддерживает opt-in виртуализацию пользовательского интерфейса начиная с 3.5SP1 через атрибут XAML:
VirtualizingStackPanel.IsVirtualizing="True"
У Bea Stollnitz есть три замечательных сообщений на эту тему, хотя она указывает, что они устарели с SP1.