If you are using a Windows Phone 7, you’ll have noticed that when you want to go through your People list they are all ‘grouped’ by one character. And when you press one of those characters, you’ll get a nice overview of all available groups, again shown by a character.
Example
Now if you are a wp7 developer and want to have the same kind of behaviour for any kind of ‘lists’ you want to present to the enduser, you have 2 options, 1. develop your own control or 2. use the LongListSelector available in the Sliverlight toolkit for WindowsPhone7!
Now to use this control, you better read up 2 posts available on windowsphonegeek
Now if you follow these posts, you’ll notice you won’t get the same look and feel as on the People list in the Windows Phone itself… now to overcome this, you’ll better read up Benjii’s post on how to use the LongListSelector!
Because when you follow his instructions, you’ll get a better UI in reference to the People list on the Windows Phone.
But somehow when I used his solution, I was not able to get a correct Item Selection Change event to Command working. Somehow Benjii’s group class won’t let me cast back to one selected item in the ViewModel.
So again I needed a solution! And after some twitter chatter and a question on stackoverflow, I was directed to a custom implementation done by Claus Jørgensen!
The best way to look at his grouping class and LongListSelector usage, is to download his weather app from GitHub!
It contains a fine example on how to use the LongListSelector and also an extension that is needed to get Command binding to the SelectionChanged event!
His Grouping class also makes it possible to get the correct item from when the selection changed event get’s fired!
I did however change one small detail of his Grouping class ( LongListCollection.cs ), because when you do nothing with Claus’ class, you’ll only see the item group keys of the available items. And Benjii’s solution, first add’s dummy key/list items so that you’ll get the same overview as on the People list, when a group has no items the group key will be greyed out!!
To get this working with Claus’ class, I added a DefaultHeaders list! Here is my implementation of the class:
1 |
<span class="kwrd">namespace</span> DepSoft.Mobile.WP7.iTunesControl.Model |
1 |
{ |
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> LongListCollection<T, TKey> : ObservableCollection<LongListItem<T, TKey>> |
1 |
<span class="kwrd">where</span> T : IComparable<T> |
1 |
{ |
1 |
<span class="preproc">#region</span> Constructor |
1 |
<span class="kwrd">public</span> LongListCollection() |
1 |
{ |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> LongListCollection(IEnumerable<T> items, Func<T, TKey> keySelector, List<TKey> defaultHeaders) |
1 |
{ |
1 |
<span class="kwrd">if</span> (items == <span class="kwrd">null</span>) |
1 |
<span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">"items"</span>); |
1 |
  |
1 |
var groups = <span class="kwrd">new</span> Dictionary<TKey, LongListItem<T, TKey>>(); |
1 |
<span class="kwrd">this</span>.FillGroup(groups, defaultHeaders); |
1 |
  |
1 |
<span class="kwrd">foreach</span> (var item <span class="kwrd">in</span> items.OrderBy(x => x)) |
1 |
{ |
1 |
var key = keySelector(item); |
1 |
  |
1 |
<span class="kwrd">if</span> (groups.ContainsKey(key) == <span class="kwrd">false</span>) |
1 |
groups.Add(key, <span class="kwrd">new</span> LongListItem<T, TKey>(key)); |
1 |
  |
1 |
groups[key].Add(item); |
1 |
} |
1 |
  |
1 |
<span class="kwrd">foreach</span> (var <span class="kwrd">value</span> <span class="kwrd">in</span> groups.Values) |
1 |
<span class="kwrd">this</span>.Add(<span class="kwrd">value</span>); |
1 |
} |
1 |
<span class="preproc">#endregion</span> |
1 |
  |
1 |
<span class="preproc">#region</span> Private methods |
1 |
<span class="kwrd">private</span> <span class="kwrd">void</span> FillGroup(Dictionary<TKey, LongListItem<T, TKey>> groups, List<TKey> defaultHeaders) |
1 |
{ |
1 |
<span class="kwrd">foreach</span> (TKey key <span class="kwrd">in</span> defaultHeaders) |
1 |
{ |
1 |
<span class="kwrd">if</span> (!groups.ContainsKey(key)) |
1 |
groups.Add(key, <span class="kwrd">new</span> LongListItem<T, TKey>(key)); |
1 |
} |
1 |
} |
1 |
<span class="preproc">#endregion</span> |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> <span class="kwrd">class</span> LongListItem<T, TKey> : ObservableCollection<T> |
1 |
{ |
1 |
<span class="kwrd">public</span> LongListItem() |
1 |
{ |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> LongListItem(TKey key) |
1 |
{ |
1 |
<span class="kwrd">this</span>.Key = key; |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> TKey Key |
1 |
{ |
1 |
get; |
1 |
set; |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> <span class="kwrd">bool</span> HasItems |
1 |
{ |
1 |
get |
1 |
{ |
1 |
<span class="kwrd">return</span> Count > 0; |
1 |
} |
1 |
} |
1 |
  |
1 |
<span class="kwrd">public</span> Brush GroupBackgroundBrush |
1 |
{ |
1 |
get |
1 |
{ |
1 |
<span class="kwrd">if</span> (HasItems) |
1 |
<span class="kwrd">return</span> (SolidColorBrush)Application.Current.Resources[<span class="str">"PhoneAccentBrush"</span>]; |
1 |
<span class="kwrd">else</span> |
1 |
<span class="kwrd">return</span> (SolidColorBrush)Application.Current.Resources[<span class="str">"PhoneChromeBrush"</span>]; |
1 |
} |
1 |
} |
1 |
} |
1 |
} |
Now if you want to use this in your ViewModel, you only need to add the following 2 lines:
1 |
List<<span class="kwrd">char</span>> defaultHeaders = <span class="kwrd">new</span> List<<span class="kwrd">char</span>>(<span class="str">"#abcdefghijklmnopqrstuvwxyz"</span>); |
1 |
<span class="kwrd">this</span>.ListGroup = <span class="kwrd">new</span> LongListCollection<iBaseItem, <span class="kwrd">char</span>>(albumList.Cast<iBaseItem>(), c => c.GroupHeader[0], defaultHeaders); |
I hope you guys have as much fun with the LongListSelector as I did 😉