Compartilhar via


10 reasons to consider WPF for your next desktop application - Reason 7. The ListView

This is the 7th post in the series 10 reasons to consider WPF for your next desktop application by Josh Twist, this part explores the ListView in WPF.

You can view the other reasons in the series below:

Earlier I introduced a series of posts entitled 10 reasons to consider WPF for your next desktop application. If you haven't read the intro yet, better head on back and read it first.

Long term readers of this blog may recall my love of the ListView in Windows Forms. In the post that introduced my PropertyListView control I briefly mentioned why I'm a big fan of the ListView.

"I use the ListView control in my WinForm applications a lot. I mainly use it in Details mode where you get multiple columns just like you do in Windows Explorer. This is also the reason I use it so much - it's familiar and it looks good too. "

Well I've got some good news for likeminded ListView fans - things just got much better with WPF.

As with all things WPF, databinding has been baked into the ListView from the start and it works a treat. To create a simple list using the same object model as the previous examples in this series is as easy as this:

<ListView x:Name="_lstBooks" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name" />
<GridViewColumn DisplayMemberBinding="{Binding Author}" Header="Author" />
<GridViewColumn DisplayMemberBinding="{Binding CustomerRating}" Header="Customer Rating" />
</GridView>
</ListView.View>
</ListView>

Basic List View

And if we wanted to use our funky RatingBar from "My dirty little secret from Reason 3. ControlTemplates" it's as easy as specifying the cell's template using a good old DataTemplate:

<GridViewColumn Header="Customer Rating">
<GridViewColumn.CellTemplate>
<DataTemplate>
<src:RatingBar Template="{StaticResource ratingBarTemplate}"
Maximum="5" Value="{Binding CustomerRating}"
Width="100" Height="20" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Basic List View showing the RatingBar

Neat. But what else can it do?

In two recent posts (Binding to the Current Item and How binding to the Current Item works) I discussed how, when binding to a collection in WPF for any type of ItemsControl, an underlying CollectionViewSource is created and this can be reached using CollectionViewSource.GetDefaultView(object source). This returns an implemetation of the ICollectionView interface which has two properties I want to look at: SortDescriptions and GroupDescriptions.

SortDescriptions

You've probably guessed by now that the SortDescriptions property allows me to sort my collection. Bingo, and it's as easy as this:

ICollectionView icv = CollectionViewSource.GetDefaultView(_books);
icv.SortDescriptions.Add(new SortDescription("Author", ListSortDirection.Ascending));

I don't really need to explain that - suffice to point out that performing a sort changes the order that items appear in the ListView. In fact, I've talked about this in more detail in my post about creating a Sortable ListView where we used Attached Properties and the natural extensibility of WPF to create a SortableListView control that will automatically sort items when the user clicks the column header.

GroupDescriptions

Again, you've probably guessed that the GroupDescriptions property has something to do with the grouping of items and you'd be right. Programmatically it's just as easy to group an ICollectionView:

ICollectionView icv = CollectionViewSource.GetDefaultView(_books);
icv.GroupDescriptions.Add(new PropertyGroupDescription("CustomerRating"));

However, doing this alone will have no impact on your GridView based ListView. We need to specify what the grouping should look like and we call on our old friend the ControlTemplate here.

<ListView x:Name="_lstBooks" Grid.Row="1" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderBrush="Black" BorderThickness="0,0,0,1" Background="Navy">
<Expander.Header>
<TextBlock Foreground="White">
<Run>Customer Rating: </Run>
<TextBlock FontWeight="Bold"
Text="{Binding Path=Name}" />
<TextBlock Text=" ("/>
<TextBlock
Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" items)" />
</TextBlock>
</Expander.Header>
<Expander.Content>
<Border Background="White" Margin="2" CornerRadius="3">
<ItemsPresenter />
</Border>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
...
</ListView>

Basic List View showing the RatingBar

As you can see, grouping now works a treat and we've wrapped each group in an Expander control. Why not have a play with the Reason 7 ClickOnce sample to see for yourself.

Originally posted by Josh Twist on 17th November 2007 here.

Comments