Search code examples
windows-phone-7data-bindingexpression-blend

How to format sample design-time data for a LongListSelector?


I'd like to use a designer (e.g. Expression Blend) to template the LongListSelector control (from the SL toolkit for WP7), but I can't figure out how to format the data to fit what this control expects.

Any pointers to a tutorial would be appreciated. Thanks.


Solution

  • Use a specialized collection, like this:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using System.Collections.ObjectModel;
    
    namespace Stackoverflow.Collections
    {
        /// <summary>
        /// Represents a specialized collection to integrate with the 
        /// <see cref="Microsoft.Phone.Controls.LongListSelector"/> control.
        /// </summary>
        /// <typeparam name="T">The type of the values in the collection.</typeparam>
        /// <typeparam name="TKey">The type of the keys in the collection.</typeparam>
        public class LongListCollection<T, TKey> : ObservableCollection<LongListItem<T, TKey>>
            where T : IComparable<T>
            where TKey : IComparable<TKey>
        {
            /// <summary>
            /// The key selector for adding items.
            /// </summary>
            private Func<T, TKey> keySelector;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="LongListCollection&lt;T, TKey&gt;"/> class.
            /// </summary>
            /// <param name="keySelector">The key selector.</param>
            public LongListCollection(Func<T, TKey> keySelector)
            {
                if (keySelector == null)
                    throw new ArgumentNullException("keySelector");
    
                this.keySelector = keySelector;
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="LongListCollection&lt;T, TKey&gt;"/> class.
            /// </summary>
            /// <param name="keySelector">The key selector.</param>
            /// <param name="items">A initial collection.</param>
            public LongListCollection(Func<T, TKey> keySelector, IEnumerable<T> items)
            {
                if (keySelector == null)
                    throw new ArgumentNullException("keySelector");
    
                if (items == null)
                    throw new ArgumentNullException("items");
    
                this.keySelector = keySelector;
    
                var groups = new Dictionary<TKey, LongListItem<T, TKey>>();
    
                foreach (var item in items.OrderBy(x => x))
                {
                    var key = keySelector(item);
    
                    if (groups.ContainsKey(key) == false)
                        groups.Add(key, new LongListItem<T, TKey>(key));
    
                    groups[key].Add(item);
                }
    
                foreach (var value in groups.Values)
                    this.Add(value);
            }
    
            /// <summary>
            /// Adds the specified item to the collection.
            /// </summary>
            /// <param name="item">The item.</param>
            public void Add(T item)
            {
                TKey key = keySelector(item);
    
                var group = this.FirstOrDefault(x => x.Key.Equals(key));
                if (group != null)
                    group.Add(item);                
                else
                    this.Add(new LongListItem<T, TKey>(key) { item });
            }
    
            /// <summary>
            /// Inserts an item into the collection at the specified index.
            /// </summary>
            /// <param name="index">The zero-based index at which item should be inserted.</param>
            /// <param name="item">The object to insert.</param>
            protected override void InsertItem(int index, LongListItem<T, TKey> item)
            {
                for (int i = 0; i < this.Count; i++)
                {
                    switch (Math.Sign(this[i].CompareTo(item)))
                    {
                        case 0:
                            throw new InvalidOperationException("Cannot insert duplicated items.");
                        case 1:
                            base.InsertItem(i, item);
                            return;
                        case -1:
                            break;
                    }
                }
    
                base.InsertItem(this.Count, item);
            }
        }
    
        /// <summary>
        /// Represents a specialized data structure to integrate with the 
        /// <see cref="Microsoft.Phone.Controls.LongListSelector"/> control.
        /// </summary>
        /// <typeparam name="T">The type of the values in the structure.</typeparam>
        /// <typeparam name="TKey">The type of the key in the structure.</typeparam>
        public class LongListItem<T, TKey> : ObservableCollection<T>, IComparable<LongListItem<T, TKey>>
            where T : IComparable<T>
            where TKey : IComparable<TKey>
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="LongListItem&lt;T, TKey&gt;"/> class.
            /// </summary>
            public LongListItem()
            {
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="LongListItem&lt;T, TKey&gt;"/> class.
            /// </summary>
            /// <param name="key">The item's key.</param>
            public LongListItem(TKey key)
            {
                this.Key = key;
            }
    
            /// <summary>
            /// Gets or sets the item key.
            /// </summary>
            /// <value>The item key.</value>
            public TKey Key
            {
                get;
                set;
            }
    
            /// <summary>
            /// Gets a value indicating whether this instance has any items.
            /// </summary>
            /// <value><c>true</c> if this instance has any items; otherwise, <c>false</c>.</value>
            public bool HasItems
            {
                get
                {
                    return Count > 0;
                }
            }
    
            /// <summary>
            /// Inserts an item into the collection at the specified index.
            /// </summary>
            /// <param name="index">The zero-based index at which item should be inserted.</param>
            /// <param name="item">The object to insert.</param>
            protected override void InsertItem(int index, T item)
            {                              
                for (int i = 0; i < this.Count; i++)
                {
                    switch (Math.Sign(this[i].CompareTo(item)))
                    {
                        case 0:
                            return;
                        case 1:
                            base.InsertItem(i, item);
                            return;
                        case -1:
                            break;
                    }
                }
    
                base.InsertItem(this.Count, item);
            }
    
            /// <summary>
            /// Compares to.
            /// </summary>
            /// <param name="other">The other.</param>
            /// <returns></returns>
            public int CompareTo(LongListItem<T, TKey> other)
            {
                if (other == null)
                    return 1;
    
                return this.Key.CompareTo(other.Key);
            }
        }
    }