Introduction
Data filtering and sorting are important features of .NET since it was introduced over 10 years ago. The
DataTable class has supported both since .NET 1.0.
When WPF came along, it introduced the ICollectionView interface, which in addition to
sorting and filtering supports grouping and currency (the notion of a current item).
Surprisingly, the ICollectionView interface specified in the WinRT version of the system libraries does
not support sorting, filtering, or grouping. In WinRT, you can show a list of items on a grid, but there
is no standard method for sorting or filtering this data.
This article describes ICollectionViewEx, an extended version of the
ICollectionView interface and the implementation of a ListCollectionView
class that implements it. With this class, you can add sorting and filtering to your data the same way you do
it in your WPF, Silverlight, and Windows Phone applications.
The ListCollectionView class also implements the IEditableCollectionView
interface, which allows advanced controls such as data grids to implement advanced editing features like
canceling edits and adding new items.
The article includes a sample that demonstrates how you can use the ListCollectionView class to
implement search box similar to the one found in applications such as iTunes. The search box applies a
filter to the data source and selects items that contain all the terms typed in by the user in any of
their properties. The filtered data can be used as a regular data source for any controls, even if they
know nothing about the ICollectionViewEx interface.
Even though the sample is a Windows Store application, it uses the MVVM model and the
ICollectionViewEx
interface, which would make it trivial to create versions for Silverlight, WPF, or Windows Phone.
Note that ListCollectionView class does not implement grouping. That is a more advanced
feature that will be left as an exercise for the reader.
The ICollectionViewEx Interface
The IColletionViewEx interface inherits from the standard
ICollectionView interface and adds the members
that are missing in the WinRT edition:
public interface ICollectionViewEx : ICollectionView
{
bool CanFilter { get; }
Predicate<object> Filter { get; set; }
bool CanSort { get; }
IList<SortDescription> SortDescriptions { get; }
bool CanGroup { get; }
IList<object> GroupDescriptions { get; }
IEnumerable SourceCollection { get; }
IDisposable DeferRefresh();
void Refresh();
}
In addition to the members related to filtering and sorting, which we will implement later, the interface
also has members related to grouping, for exposing the view’s SourceCollection, and for refreshing the
view or deferring refreshes while the view is being modified.
All these elements are present in the WPF version of ICollectionView, and there are many libraries that rely
on these being present.
The interface definition uses a SortDescription class and a
ListSortDirection enum that also have to be
defined:
public class SortDescription
{
public SortDescription(string propertyName, ListSortDirection direction)
{
PropertyName = propertyName;
Direction = direction;
}
public string PropertyName { get; set; }
public ListSortDirection Direction { get; set; }
}
public enum ListSortDirection
{
Ascending = 0,
Descending = 1,
}
The IEditableCollectionView Interface
The IEditableCollectionView interface is also missing from WinRT. It exposes functionality used to
provide advanced editing (allowing users to cancel edits) and adding items to the collection:
public interface IEditableCollectionView
{
bool CanAddNew { get; }
bool CanRemove { get; }
bool IsAddingNew { get; }
object CurrentAddItem { get; }
object AddNew();
void CancelNew();
void CommitNew();
bool CanCancelEdit { get; }
bool IsEditingItem { get; }
object CurrentEditItem { get; }
void EditItem(object item);
void CancelEdit();
void CommitEdit();
}
The first part of the interface deals with adding items to the collection. It is used by controls
such as grids, which often expose a template for new rows where users can create elements simply by
filling the template.
The second part deals with editing items. This is important because you don’t want to apply
any sorting or filtering to a collection while an item is being edited. Doing so could cause the
item to change position in the collection or even to be filtered out of view before you are done
editing it. Also, the interface defines a CancelEdit method that restores the original state of the object,
undoing all edits.
The ListCollectionView Class
The ListCollectionView class implements the ICollectionViewEx and IEditableCollectionView interfaces. It
can be used like a regular WPF ListCollectionView. For example:
var list = new List<Rect>();
for (int i = 0; i < 10; i++)
list.Add(new Rect(i, i, i, i));
var view = new ListCollectionView(list);
view.Filter = (item) => { return ((Rect)item).X > 5; };
view.SortDescriptions.Add(new SortDescription("X", ListSortDirection.Descending));
foreach (var r in view)
Console.WriteLine(r);
Running this code produces the output you would expect:
9,9,9,9
8,8,8,8
7,7,7,7
6,6,6,6
The ListCollectionView class works as follows:
-
It has a source collection that contains a list of elements. The source collection is exposed by the
SourceCollection property. (If you want the ability to change the collection by adding and removing
items, the source collection should implement the INotifyCollectionChanged interface, for example the
ObservableCollection class).
-
It has a filter predicate that selects which members of the source collection should be included in
the view. The filter predicate is a function that takes an object as a parameter and returns true
if the object should be included in the view, and false otherwise. By default, the filter is set to null,
which causes all elements to be included in the view. The filter predicate is exposed by the
Filter
property.
-
It has a collection of sort descriptors that specify which properties should be used to sort the
elements included in the view and the sort direction. The sort descriptors are exposed by the
SortDescriptors property.
-
Finally, the view is a filtered and sorted list of elements. It is updated automatically when any of
the three elements listed above change. The main challenge involved in implementing the
ListCollectionView class is performing the updates efficiently.
The diagram below shows how these elements interact:

The ListCollectionView class listens to changes in the SourceCollection and
SortDescriptors
collections, and also to changes in the value of the Filter property.
When changes are detected in the SortDescriptors or
Filter, the View collection is fully
re-generated and the class raises a Reset notification to all listeners.
When changes are detected in the SourceCollection, the class tries to perform a minimal
update.
For example, if a single item is added to the source, it is tested against the current filter.
If the filter rejects the item, no further action is required. If the filter accepts the item
(or if there is no filter), the item is inserted at the proper place in the view, taking the
current sort into account. In this case, the class raises an ItemAdded notification.
Similarly, if a single item is deleted from the source and is present in the view, the item
is simply removed from the view and an ItemRemoved notification is raised.
The minimal update feature improves application performance because it minimizes the number
of full refresh notifications raised by the class. Imagine for example a data grid showing
thousands of items. An item added event can be handled by creating a new row and inserting
it at the proper position in the control. A full refresh, by contrast, would require the
control to dispose of all its current rows and then create new ones.
Now that we know how the ListCollectionView is supposed to work, let’s look at the implementation.
The ListCollectionView constructors are implemented as follows:
public class ListCollectionView :
ICollectionViewEx,
IEditableCollectionView,
IComparer<object>
{
public ListCollectionView(object source)
{
_view = new List<object>();
_sort = new ObservableCollection<SortDescription>();
_sort.CollectionChanged += _sort_CollectionChanged;
Source = source;
}
public ListCollectionView() : this(null) { }
The constructor creates a _view list that will contain the filtered and sorted output
list. It also creates a _sort collection that contains a list of sort descriptors to
be applied to the view. The _sort collection is observable, so whenever it changes
the view can be refreshed to show the new sort order.
Finally, the constructor sets the Source property to the source collection. Here is how the
Source
property is implemented:
public object Source
{
get { return _source; }
set
{
if (_source != value)
{
_source = value;
if (_sourceNcc != null)
_sourceNcc.CollectionChanged -= _sourceCollectionChanged;
_sourceNcc = _source as INotifyCollectionChanged;
if (_sourceNcc != null)
_sourceNcc.CollectionChanged += _sourceCollectionChanged;
HandleSourceChanged();
}
}
}
The setter stores a reference to the new source, connects a handler to its
CollectionChanged
event if that is available, and calls the HandleSourceChanged method to populate the view.
The HandleSourceChanged method is where things start to get interesting:
void HandleSourceChanged()
{
var currentItem = CurrentItem;
_view.Clear();
var ie = Source as IEnumerable;
if (ie != null)
{
foreach (var item in ie)
{
if (_filter == null || _filter(item))
{
if (_sort.Count > 0)
{
var index = _view.BinarySearch(item, this);
if (index < 0) index = ~index;
_view.Insert(index, item);
}
else
{
_view.Add(item);
}
}
}
}
OnVectorChanged(VectorChangedEventArgs.Reset);
CurrentItem = currentItem;
}
The HandleSourceChanged method performs a full refresh on the view. It starts by removing any
existing items from the view. Then it enumerates the items in the source, applies the filter,
and adds them to the view.
If the _sort list contains any members, then the view is sorted, and the position where the new
item should be inserted is determined by calling the BinarySearch method provided by the
List class.
Finally, the method calls the OnVectorChanged member to raise the
VectorChanged event that is
responsible for notifying any clients bound to the view.
If we were not concerned about efficiency, we could stop here. Calling the
HandleSourceChanged
method after any changes in the source collection or the filter/sort parameters would work.
The only problem is it would work slowly. Any controls bound to the view would have to do a full
refresh whenever a single item was added or removed from the source for example.
The ListCollectionView class has methods that deal with item addition and removal very efficiently.
These methods are implemented as follows:
void HandleItemRemoved(int index, object item)
{
if (_filter != null && !_filter(item))
return;
if (index < 0 || index >= _view.Count || !object.Equals(_view[index], item))
index = _view.IndexOf(item);
if (index < 0)
return;
_view.RemoveAt(index);
if (index <= _index)
_index--;
var e = new VectorChangedEventArgs(CollectionChange.ItemRemoved, index, item);
OnVectorChanged(e);
}
The HandleItemRemoved method starts by checking whether the item that was removed from the
source has not been filtered out of the view. If that is the case, then the view hasn’t
changed and nothing needs to be updated.
Next, the method determines the index of the item removed in the current view. If the view
is filtered or sorted, the index passed to the method is invalid, and the actual index is
determined by calling the IndexOf method. Once the item index is known, the item is removed from the view.
If the item removed was above the view’s current item (determined by the _index variable),
then the view’s index is adjusted so the current item remains current. In this case, the view’s
CurrentPosition property will change, but the CurrentItem property will remain the same.
Finally, the method calls the OnVectorChanged event to notify listeners that the view has changed.
The HandleItemAdded method is responsible for updating the view when items are added to the
source collection:
void HandleItemAdded(int index, object item)
{
if (_filter != null && !_filter(item))
return;
if (_sort.Count > 0)
{
_sortProps.Clear();
index = _view.BinarySearch(item, this);
if (index < 0) index = ~index;
}
else if (_filter != null)
{
var visibleBelowIndex = 0;
for (int i = index; i < _sourceList.Count; i++)
{
if (!_filter(_sourceList[i]))
visibleBelowIndex++;
}
index = _view.Count - visibleBelowIndex;
}
_view.Insert(index, item);
if (index <= _index)
_index++;
var e = new VectorChangedEventArgs(CollectionChange.ItemInserted, index, item);
OnVectorChanged(e);
}
As before, the method starts by checking whether the item that was added to the original
collection should be included in the view. If not, then there’s no work to be done.
Next, the method determines the index where the new item should have in the view. If the
view is sorted, the index is determined by calling the BinarySearch method as before. This
will work whether or not the view is filtered.
If the view is not sorted, but is filtered, then the index of the item in the view is
determined by counting how many items in the source collection are below the new item
and are not filtered out of view. The index of the item in the view is then obtained by
subtracting this number from the number of items in the view. This ensures that items will
appear in the view in the same order they appear in the source list.
Once the item index is known, the item is added to the view.
As before, the view’s index is updated if the new item was inserted above the view’s
current item.
Finally, the method calls the OnVectorChanged event to notify listeners that the view has changed.
Now that we have the three update methods in place, the next step is to call them from the right places: first, we call HandleSourceChanged when the sort descriptor collection or the filter predicate change.
In both cases, the view has to be completely refreshed:
public Predicate<object> Filter
{
get { return _filter; }
set
{
if (_filter != value)
{
_filter = value;
HandleSourceChanged();
}
}
}
void _sort_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
HandleSourceChanged();
}
Next, we call the appropriate method when the source collection changes:
void _sourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.NewItems.Count == 1)
HandleItemAdded(e.NewStartingIndex, e.NewItems[0]);
else
HandleSourceChanged();
break;
case NotifyCollectionChangedAction.Remove:
if (e.OldItems.Count == 1)
HandleItemRemoved(e.OldStartingIndex, e.OldItems[0]);
else
HandleSourceChanged();
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
HandleSourceChanged();
break;
default:
throw new Exception(
"Unrecognized collection change notification" +
e.Action.ToString());
}
}
Finally, we call the HandleSourceChanged method in response to the
Refresh method, which is public:
public void Refresh()
{
HandleSourceChanged();
}
This concludes the implementation of the filtering and sorting logic.
Deferred Notifications
Deferred notifications allow callers to suspend change notifications while they make extensive
changes to the view. For example, suspending notifications is usually a good idea when adding
items in bulk or applying several filter definitions.
The deferred notification mechanism in the ICollectionViewEx interface is exposed by a single
member, the DeferRefresh method. The method is implemented as follows:
public IDisposable DeferRefresh()
{
return new DeferNotifications(this);
}
class DeferNotifications : IDisposable
{
ListCollectionView _view;
object _currentItem;
internal DeferNotifications(ListCollectionView view)
{
_view = view;
_currentItem = _view.CurrentItem;
_view._updating++;
}
public void Dispose()
{
_view.MoveCurrentTo(_currentItem);
_view._updating--;
_view.Refresh();
}
}
The DeferRefresh method returns an internal DeferNotifications object that implements the
IDisposable interface. The usage pattern is as follows:
using (view.DeferRefresh())
{
}
The call to DeferRefresh creates a DeferNotifications object that increments
the _updating counter in the ListCollectionView. While the _updating
counter is greater than zero, the view will not raise any notifications.
At the end of the block, the DeferNotifications object goes out of scope, which automatically
invokes its Dispose method. The Dispose method decrements the
_updating counter and calls the Refresh method to restore the updates.
This pattern is better than the alternative BeginUpdate/EndUpdate methods
because it makes very easy to scope the part of the code where notifications are suspended.
It also makes sure notifications are properly restored even if there are
exceptions within the code block (you don't have to write an explicit 'finally'
clause).
Other ICollectionView Methods
The sections above discussed the implementation of the sorting and filtering methods which are
present in the ICollectionViewEx but are not in the WinRT version of the
ICollectionView
interface.
Because the ICollectionViewEx interface inherits from
ICollectionView, our ListCollectionView
class must also implement those methods.
Fortunately, those methods are relatively simple. They fall into two broad categories:
-
List operations:
The
ListCollectionView class delegates list operations to its _sourceList
field, which is simply the source collection cast to an IList object that provides all
the methods needed (such as Add, Remove, Contains,
IndexOf, etc). If the source collection is not an IList, then the
IsReadOnly property will return true and none of these methods will be available.
-
Cursor operations: The
ListCollectionView class keeps track of which
item is currently selected, and exposes this information through members such as the
CurrentItem and CurrentPosition properties, several
MoveCurrentTo methods, and CurrentChanging/
CurrentChanged events. All of these properties, methods, and events are controlled
by the _index property that was mentioned earlier.
Because these methods are so simple, we will not list them here. Please refer to the source code
if you are interested in the implementation details.
IEditableCollectionView Implementation
The IEditableCollectionView implementation is relatively simple.
The first part of the interface is related to editing items. The code is as follows:
object _editItem;
public bool CanCancelEdit { get { return true; } }
public object CurrentEditItem { get { return _editItem; } }
public bool IsEditingItem { get { return _editItem != null; } }
public void EditItem(object item)
{
var ieo = item as IEditableObject;
if (ieo != null && ieo != _editItem)
ieo.BeginEdit();
_editItem = item;
}
public void CancelEdit()
{
var ieo = _editItem as IEditableObject;
if (ieo != null)
ieo.CancelEdit();
_editItem = null;
}
public void CommitEdit()
{
if (_editItem != null)
{
var item = _editItem;
var ieo = item as IEditableObject;
if (ieo != null)
ieo.EndEdit();
_editItem = null;
HandleItemChanged(item);
}
}
The implementation consists of keeping track of the object being edited and calling its
IEditableObject methods at the proper times. This allows a user to type the escape key while
editing an object in a data grid, for example, to cancel all the edits and restore the object’s
original state.
The CommitEdit method calls the HandleItemChanged method to ensure that the new item is properly
filtered and sorted in the view.
The second part of the IEditableCollectionView interface is related to adding items to the view,
and is implemented as follows:
object _addItem;
public bool CanAddNew { get { return !IsReadOnly && _itemType != null; } }
public object AddNew()
{
_addItem = null;
if (_itemType != null)
{
_addItem = Activator.CreateInstance(_itemType);
if (_addItem != null)
this.Add(_addItem);
}
return _addItem;
}
public void CancelNew()
{
if (_addItem != null)
{
this.Remove(_addItem);
_addItem = null;
}
}
public void CommitNew()
{
if (_addItem != null)
{
var item = _addItem;
_addItem = null;
HandleItemChanged(item);
}
}
public bool CanRemove { get { return !IsReadOnly; } }
public object CurrentAddItem { get { return _addItem; } }
public bool IsAddingNew { get { return _addItem != null; } }
The AddNew method creates new elements of the appropriate type using the
Activator.CreateInstance method.
New items are appended to the view and are not sorted or filtered until the
CommitNew method is called.
This logic allows controls such as data grids to provide a “new row” template. When the user starts typing
into the template, an item is automatically added to the view. When the user moves the cursor to a new row
on the grid, it calls the CommitNew method and the view is refreshed. If the user presses the escape key
before committing the new row, the data grid calls the CancelNew method and the new item is removed from
the view.
MyTunes Sample Application
To demonstrate how you can use the ListCollectionView class, we created a simple MVVM application called
MyTunes. The application loads a list of songs from a resource file and displays the songs in a
GridView
control.
The user can search for songs by typing terms into a search box. For example, typing “hendrix love” will
show only songs that contain the words “hendrix” and “love” in their title, album, or artist name. The
user can also sort the songs by title, album, or artist by clicking one of the buttons above the list.
The image below shows what the application looks like:

The MyTunes ViewModel
The ViewModel class exposes a collection of songs and methods to filter and sort the collection. Here is the
declaration and constructor:
public class ViewModel : INotifyPropertyChanged
{
ListCollectionView _songs;
string _filterTerms;
Storyboard _sbUpdateFilter;
ICommand _cmdSort;
public ViewModel()
{
_songs = new ListCollectionView();
_songs.Source = Song.GetAllSongs();
_songs.Filter = FilterSong;
var sd = new SortDescription("Artist", ListSortDirection.Ascending);
_songs.SortDescriptions.Add(sd);
_sbUpdateFilter = new Storyboard();
_sbUpdateFilter.Duration = new Duration(TimeSpan.FromSeconds(1));
_sbUpdateFilter.Completed += (s,e) =>
{
_songs.Refresh();
};
_cmdSort = new SortCommand(this);
}
The constructor starts by declaring a ListCollectionView to hold the songs, setting its
Source
property to a raw list of songs loaded from a local resource, and setting the Filter property
to a FilterSong method that is responsible for selecting the songs that will be included in
the view. It also initializes the SortDescriptions property to sort the songs by artist by default.
Next, the constructor sets up a StoryBoard that will be used to refresh the view one second after
the user stops changing the search terms. This is more useful than refreshing the list after each
keystroke.
Finally, the constructor creates an ICommand object that will be responsible for sorting the view
according to different properties.
The object model for the ViewModel class is implemented as follows:
public ICollectionView Songs
{
get { return _songs; }
}
public ICommand SortBy
{
get { return _cmdSort; }
}
public string FilterTerms
{
get { return _filterTerms; }
set
{
if (value != FilterTerms)
{
_filterTerms = value;
OnPropertyChanged("FilterTerms");
_sbUpdateFilter.Stop();
_sbUpdateFilter.Seek(TimeSpan.Zero);
_sbUpdateFilter.Begin();
}
}
}
The ViewModel has only three properties.
The Songs property exposed the filtered and sorted collection as a standard
ICollectionView.
This is the property that will be bound to the ItemsSource property of the control responsible
for showing the songs. In our sample this will be a GridView control.
The SortBy property exposes an ICommand object that will be bound to the
Command property on
buttons used to sort the collection.
Finally, the FilterTerms property contains a string with terms that will be used to search
the list. When the property value changes, the code starts a Storyboard that will refresh the
view after a one second delay. This is done so users can type into a search box without having
the view refresh after each keystroke.
The remaining parts of the implementation are as follows:
bool FilterSong(object song)
{
if (string.IsNullOrEmpty(FilterTerms))
return true;
foreach (var term in this.FilterTerms.Split(' '))
{
if (!FilterSongTerm((Song)song, term))
return false;
}
return true;
}
static bool FilterSongTerm(Song song, string term)
{
return
string.IsNullOrEmpty(term) ||
song.Name.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 ||
song.Album.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 ||
song.Artist.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}}
The FilterSong method, assigned to the ListCollectionView’s
Filter property in the constructor,
is responsible for determining which songs should be included in the view. It does this by
splitting the filter terms into an array of strings and returning true only for songs that
contain all terms in their Name, Album, or
Artist property.
The SortCommand class exposed by the ViewModel’s
SortBy property is implemented as follows:
class SortCommand : ICommand
{
ViewModel _vm;
public SortCommand(ViewModel vm)
{
_vm = vm;
var cv = _vm.Songs as ListCollectionView;
if (cv != null)
{
cv.VectorChanged += (s, e) =>
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
};
}
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
var prop = parameter as string;
var cv = _vm.Songs as ListCollectionView;
if (cv == null || string.IsNullOrEmpty(prop))
return false;
if (cv.SortDescriptions.Count > 0 &&
cv.SortDescriptions[0].PropertyName == prop)
return false;
return true;
}
public void Execute(object parameter)
{
var prop = parameter as string;
var cv = _vm.Songs as ListCollectionView;
if (cv != null && !string.IsNullOrEmpty(prop))
{
using (cv.DeferRefresh())
{
cv.SortDescriptions.Clear();
var sd = new SortDescription(
prop,
ListSortDirection.Ascending);
cv.SortDescriptions.Add(sd);
}
}
}
}
The class implements a CanExecute method that returns false when the collection is already
sorted by the given parameter, and true otherwise. This causes buttons bound to the command
to be automatically disabled when the view is already sorted by that parameter.
For example, clicking the 'sort by Artist' button will sort the collection by
artist and will also disable the button until the list is sorted by some other
property.
The implementation of the Execute method consists of updating the
ListCollectionView’s
SortDescriptions property. Notice how this is done within a
DeferRefresh block so the view
will only be refreshed once.
The MyTunes View
The view is implemented in pure XAML. The interesting parts are listed below:
<Page
x:Class="MyTunes.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="using:MyTunes"
mc:Ignorable="d">
<Page.Resources>
<local:ViewModel x:Key="_vm" />
<local:DurationConverter x:Key="_cvtDuration" />
</Page.Resources>
<Grid
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
DataContext="{StaticResource _vm}">
<Grid.RowDefinitions…>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
This code creates an instance of the ViewModel class and assigns it to the
DataContext property
of the element that will serve as the layout root.
The content of the page is as follows:
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="MyTunes" FontSize="48" />
<StackPanel Orientation="Horizontal"
Grid.Column="1" Margin="12" VerticalAlignment="Center">
<TextBlock Text="Sort" />
<Button Content="By Song"
Command="{Binding SortBy}" CommandParameter="Name"/>
<Button Content="By Album"
Command="{Binding SortBy}" CommandParameter="Album"/>
<Button Content="By Artist"
Command="{Binding SortBy}" CommandParameter="Artist"/>
<TextBlock Text="Search" />
<local:ExtendedTextBox
Width="300" Margin="8 0" VerticalAlignment="Center"
Text="{Binding FilterTerms, Mode=TwoWay }" />
</StackPanel>
</Grid>
The first element is a grid that contains the application title and the command bar.
The command bar contains three buttons bound to the ViewModel’s
SortBy property and used
to sort the view by song Name, Album, or
Artist. The buttons are automatically disabled
when the view is sorted by the property they represent, courtesy of the
SortCommand
class described earlier.
After the sort buttons, the command bar contains a text box bound to the
ViewModel’s
FilterTerms property.
Notice that we did not use a standard TextBox control. The reason for that is the WinRT
TextBox only updates its binding source when it loses focus. In our app, the filter should
be updated as the user types. To get the instant update behavior we want, we used the
ExtendedTextBox control available on CodePlex:
https://mytoolkit.svn.codeplex.com/svn/WinRT/Controls/ExtendedTextBox.cs
The final piece of the view is the GridView element that will show the songs:
<GridView ItemsSource="{Binding Songs}" Grid.Row="1" >
<GridView.ItemTemplate>
<DataTemplate>
<Border Margin="10" Padding="20" Background="#20c0c0c0" >
<StackPanel Width="350">
<TextBlock Text="{Binding Name}" FontSize="20" />
<TextBlock Text="{Binding Album}" />
<TextBlock>
<Run Text="{Binding Artist}" />
<Run Text=" (" />
<Run Text="{Binding Duration,
Converter={StaticResource _cvtDuration}}" />
<Run Text=")" />
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
The GridView element is bound to the Songs property of the
ViewModel. The ItemTemplate contains
TextBlock elements bound to the properties of the Song class.
This is the complete application. The page has no code behind, as is typical in MVVM style
applications. In fact, this application would be a completely standard MVVM app in Siverlight
or in WPF. The only thing that makes it interesting is the fact that it is a WinRT (Windows Store)
application and its ViewModel provides filtering and sorting, which are not supported natively
by WinRT. That job is handled by our ListCollectionView class.
FilterControl Sample Application
In addition to the MyTunes sample, you may want to check out another interesting sample here:
http://our.componentone.com/samples/winrtxaml-filter
This sample shows how you can implement a touch-friendly FilterControl in WinRT. The
FilterControl
is bound to a collection view. As the user modifies the filter, the control updates the collection
view's Filter property and any controls bound to the collection will automatically show the filtered results.
This is what the FilterControl in the sample looks like:

To use the FilterControl, the user selects a property from the list on the left (for example "Country"). This causes the filter to show a histogram with the values of that property within the current view (for example sales for each country). The user then selects a specific value by sliding the histogram (for example sales in Germany).
The whole process makes it easy to filter your data using slide gestures, without typing, which makes this type of control great for use in tablet and phone applications.
The FilterControl allows you to attach ValueConverter objects to each property, so you can create histograms that show continents instead of specific countries or labels that describe value ranges (e.g. high, medium, and low sales).
Note that the FilterControl in the sample does not use our ICollectionViewEx interface, but a similar interface defined in a commercial package (the ComponentOne Studio for WinRT). If you want to run that sample using the ListCollectionView class presented here, you will have to make a few minor edits to the FilterControl class.
We will not get into the details for the FilterControl sample because it is beyond the scope of this article. But feeel free to download the source from the link above and use the control if you find it useful.
Conclusion
WinRT is an exciting new development platform. For me, one of its most interesting promises is
the ability to re-use existing code developed for WPF and Silverlight applications. Unfortunately,
there are some difficulties when doing this.
One problem is the fact that many names have changed (namespaces, class names, properties, events,
methods and so on). These issues can usually be resolved by adding #if blocks to
your code. This works, but your code will get a little messier and harder to maintain and debug.
A second and more serious problem is that some important functionality simply is not present in
WinRT. A good example is the ability of the TextBox control to update its binding values when the
text changes rather than when the control loses focus. In our sample application, we worked around
that problem using the ExtendedTextBox available on CodePlex.
Another example of course is the re-definition of the ICollectionView interface, which motivated
this article. In my opinion, the WinRT designers should have kept the original definition. They
could have skipped the implementation of the filtering , sorting, and grouping methods in their
own classes simply by having the CanFilter, CanSort, and
CanGroup properties always return false.
We would still have to implement that functionality, but at least we would not have to define a new
version of the interface. This approach would have made it easier to port WPF and Silverlight
controls to WinRT.
Perhaps future versions of WinRT will bring back the filtering, sorting, and grouping features of
the ICollectionView interface. Until then, we will have to rely on custom implementations such as
ListCollectionView.