views:

83

answers:

3

Now I am aware that I probably need to use a ListBox and can use the GroupStyle stuff which completely 100% fits my needs. Only thing is that I've been told that:

"Whenever a "GroupStyle" is set on the control, the panel that layouts the items changes from VirtualizingStackPanel to StackPanel (this is a hack in MS code)..."

I will need to display up to 2000 tracks using this mecahnism:

1) Does this bug still exist?

2) Is this something to worry about for up to 2000 tracks? (More like an average of 50-100)

Also, the group by will not be changed by the user. The tracks will be grouped the same way throughout the duration of the control.

A: 

It's not a bug...it's by design!

Edward Bedwell
Agreed, you can't really allow rich data templating when virtualizing w/group by.
Jeff Wilcox
A: 

As far as I know, ListBox still stops virtualisation of items when groups are applied.

Whether 2000 items would perform adequately will depend upon the complexity of the template applied to each item. I have a ListBox with a relatively simple template (about 8 TextBlocks in a horizontal StackPanel) and performance starts to degrade at around 1500 items with grouping applied. It also seems to depend upon the number of groups into which the items are aggregated, where a greater number of groups results in less performance. This is especially noticeable when scrolling for some reason.

ListBox makes dynamic grouping very easy, but if you're usually going to be grouping by album then it might be better to set the ItemsSource of your ItemsControl (maybe a ListBox) to be a collection of Album objects, each of which has a Tracks property that is itself a collection of Track objects. Assuming this, I see two options:

  1. Use nested ItemsControls in the Album DataTemplate
  2. Use a HeaderedItemsControl such as TreeView with a HierarchicalDataTemplate

In option one, you have to manage the selection manually. You could, in the simplest implementation, have the ability to select albums and tracks separately; potentially having a track selected that didn't belong to the selected album. You may be able to do without selection of an album as this isn't a concept present in the track-list view of other media players I can think of.

Solution one also has implications for keyboard navigation from the last track of one album to the first track of the next album.

Assuming the following code:

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" }
        }
    }
};

Here's some code that demonstrates option one:

<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>

Change the outer ListBox to an ItemsControl to alleviate the selection issue, as discussed. You'll have to make it look pretty though as the above looks pretty ugly.

Option two could be defined like this:

<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 supports opt-in UI virtualisation as of 3.5SP1 via the XAML attribute:

VirtualizingStackPanel.IsVirtualizing="True"

Bea Stollnitz has three great posts on this topic, though as she points out they're out of date since SP1.

Drew Noakes
A: 

Here is an excellent discussion that explains why UI virtualisation is not available for hierarchical data templates, and much of that discussion applies to grouped list boxes, given that such groupings create hierarchies.

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/18ea7bb0-3cd8-40bd-9276-ace4358b47cb/

Drew Noakes