-
Utilities
-
XAML Editors
-
Graphical Designers
-
XAML Converters
-
UI Automation
What is a CollectionView?
WPF has a powerful data binding infrastructure. It allows you to bind almost any kind of collection directly to a view. But when it comes to sorting, filtering and grouping the support of the collections is rare. That's the point where the
CollectionView
comes into play. A collection view is a
wrapper around a collection
that provides the following additional features:
-
Navigation
-
Sorting
-
Filtering
-
Grouping
How to Create and Use a CollectionView
The following example shows you how to create a collection view and bind it to a ListBox
<Window
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
>
<ListBox
ItemsSource
=
{
Binding Customers
}
/>
</Window
>
IList
<
Customer
>
customers
=
GetCustomers
(
)
;
_customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
The collection view adds support for selection tracking. If you set the property
IsSynchronizedWithCurrentItem
to
True
on the view that the collection is bound to, it automatically synchronizes the current item of the CollectionView and the View.
<ListBox
ItemsSource
=
"{Binding Customers}"
IsSynchronizedWithCurrentItem
=
"True"
/>
If you are using a MVVM (Model-View-ViewModel) pattern, you don't have to extra wire-up the
SelectedItem
of the control, because it's implicity available over the CollectionView.
IList
<
Customer
>
customers
=
GetCustomers
(
)
;
ICollectionView _customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
_customerView.
CurrentChanged
=
CustomerSelectionChanged;
private
CustomerSelectionChanged
(
object
sender, EventArgs e
)
// React to the changed selection
You can also manually control the selection from the ViewModel by calling the
MoveCurrentToFirst()
or
MoveCurrentToLast()
methods on the CollectionView.
Filtering
To filter a collection view you can define a callback method that determines if the item should be part of the view or not. That method should have the following signature:
bool Filter(object item)
. Now set the delegate of that method to the
Filter
property of the CollectionView and you're done.
ICollectionView _customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
_customerView.
Filter
=
CustomerFilter
private
bool
CustomerFilter
(
object
item
)
Customer customer
=
item
as
Customer;
return
customer.
Name
.
Contains
(
_filterString
)
;
Refresh the filter
If you change the filter criteria and you want to refresh the view, you have to call
Refresh()
on the collection view
public
string
FilterString
get
{
return
_filterString;
}
_filterString
=
value;
NotifyPropertyChanged
(
"FilterString"
)
;
_customerView.
Refresh
(
)
;
Sorting
Sorting data ascending or descending by one or multiple criterias is a common requirement for viewing data. The collection view makes it so easy to achieve this goal. Just add as many
SortDescriptions
as you like to the CollectionView
ICollectionView _customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
_customerView.
SortDescriptions
.
Add
(
new
SortDescription
(
"LastName"
, ListSortDirection.
Ascending
)
;
_customerView.
SortDescriptions
.
Add
(
new
SortDescription
(
"FirstName"
, ListSortDirection.
Ascending
)
;
Fast Sorting
The sorting technique explained above is really simple, but also quite slow for a large amount of data, because it internally uses reflection. But there is an alternative, more performant way to do sorting by providing a custom sorter.
ListCollectionView _customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
as
ListCollectionView;
_customerView.
CustomSort
=
new
CustomerSorter
(
)
;
public
class
CustomerSorter
:
IComparer
public
int
Compare
(
object
x,
object
y
)
Customer custX
=
x
as
Customer;
Customer custY
=
y
as
Customer;
return
custX.
Name
.
CompareTo
(
custY.
Name
)
;
Grouping
Grouping is another powerful feature of the CollectionView. You can define as many groups as you like by adding
GroupDescriptions
to the collection view.
Note: Grouping disables virtualization!
This can bring huge performance issues on large data sets. So be careful when using it.
ICollectionView _customerView
=
CollectionViewSource.
GetDefaultView
(
customers
)
;
_customerView.
GroupDescriptions
.
Add
(
new
PropertyGroupDescription
(
"Country"
)
)
;
To make the grouping visible in the view you have to define a special
GroupStyle
on the view.
<ListBox
ItemsSource
=
"{Binding Customers}"
>
<ListBox
.GroupStyle
>
<GroupStyle
.HeaderTemplate
>
<DataTemplate
>
<TextBlock
Text
=
"{Binding Path=Name}"
/>
</DataTemplate
>
</GroupStyle
.HeaderTemplate
>
</ListBox
.GroupStyle
>
</ListBox
>
How to create a CollectionView in XAML
It's also possible to create a CollectionView completely in XAML
<Window
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
>
<Window
.Resources
>
<CollectionViewSource
Source
=
"{Binding}"
x:Key
=
"customerView"
>
<CollectionViewSource
.GroupDescriptions
>
<PropertyGroupDescription
PropertyName
=
"Country"
/>
</CollectionViewSource
.GroupDescriptions
>
</CollectionViewSource
>
</Window
.Resources
>
<ListBox
ItemSource
=
"{Binding Source={StaticResource customerView}}"
/>
</Window
>
Hi Thomas,
the GetCustomer() is just a method on the ViewModel that returns a list of customers. I did not mentioned it in the snippet, because it's not relevant where the customers come from. It's just a data source. You can replace it by any kind of data source you like.
I hope this helps.
Christian
Love the layout, concept and training, keep it up!
I think your snippet needs a couple of changes, adding "new EventHandler(" and the "void" return type.
_customerView.CurrentChanged += new EventHandler(CustomerSelectionChanged);
private void CustomerSelectionChanged(object sender, EventArgs e)
{
// React to the changed selection
}
Regards,
Nigel
"Commented on 7.January 2010
But with out a definition for GetCustomers(), teh code can't be used! Its worthwhile you provide the whole code necessary when you write a tutorial for beginners so we dont get lost for hours! :)"
Just write whatever function or data source you like since the only thing that matters is that it returns results in form GetCustomers() returns.
hello
please help me?
this code for set group style in combo box. i can not set group style .until change combo box items then change text group!!!!
//class person
Public Class Person
Sub New(ByVal d As Integer, ByVal fm As String)
_id = d
_family = fm
End Sub
Private _family As String
Public Property Family() As String
Get
Return _family
End Get
Set(ByVal value As String)
_family = value
End Set
End Property
Private _id As Integer
Public Property ID() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
End Class
//vb.net code
Dim lst As Person() = New Person() {New Person(1, "amir"), New Person(1, "ali"), New Person(2, "hasan"), New Person(3, "ahmad")}
Dim p As New ListCollectionView(lst)
p.Filter = AddressOf compare
p.GroupDescriptions.Add(New PropertyGroupDescription("ID"))
p.SortDescriptions.Add(New ComponentModel.SortDescription("ID", ComponentModel.ListSortDirection.Ascending))
cmb1.DisplayMemberPath = "Family"
cmb1.Items.Clear()
cmb1.ItemsSource = p
Dim g As New GroupStyle
g.HeaderTemplate = New DataTemplate
g.HeaderTemplate.VisualTree = New FrameworkElementFactory(GetType(TextBlock))
With g.HeaderTemplate.VisualTree
Dim b As New Binding("ID")
b.Source = p
.SetBinding(TextBlock.TextProperty, b)
.SetValue(TextBlock.BackgroundProperty, Brushes.Gray)
.SetValue(TextBlock.HeightProperty, 25.0)
.SetValue(TextBlock.ForegroundProperty, Brushes.White)
End With
cmb1.GroupStyle.Add(g)
[color=red]Hello, dear users.[/color]
My name is James. Today i was joined in your portal. There are very nice! :) I hope we will be friends.
Appreciate song, please: [url=http://baseofmp3.com/?q=%CC%E0%F5%E0%E1%E1%E0%F2]Махаббат[/url]
I like it.
[b] John[/b].