Hi I created this small example, and I would like to expand it to support Sorting.
public class Country
{
public string Name { get; set; }
public int Sor
I don't think there is a default sort for TreeViews. You can either sort the items prior to entering them into the collection, or overwrite the ObservableCollection to include a Sort method.
I overwrite it in one of my projects:
public class SortableObservableCollection<T> : ObservableCollection<T>
{
// Constructors
public SortableObservableCollection() : base(){}
public SortableObservableCollection(List<T> l) : base(l){}
public SortableObservableCollection(IEnumerable<T> l) :base (l) {}
#region Sorting
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void Sort<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderBy(keySelector));
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void SortDescending<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderByDescending(keySelector));
}
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderBy(keySelector, comparer));
}
/// <summary>
/// Moves the items of the collection so that their orders are the same as those of the items provided.
/// </summary>
/// <param name="sortedItems">An <see cref="IEnumerable{T}"/> to provide item orders.</param>
private void InternalSort(IEnumerable<T> sortedItems)
{
var sortedItemsList = sortedItems.ToList();
foreach (var item in sortedItemsList)
{
Move(IndexOf(item), sortedItemsList.IndexOf(item));
}
}
#endregion // Sorting
}
You would then sort it by calling something like
Countries.Sort(country => country.SortOrder);
I like overwriting it because it let me add additional functionality to it as well such as IndexOf
or AddRange
/RemoveRange
I developed a View Model library which does a number of things, including letting you display hierarchical data in sorted order. The library is described in this article. The piece doesn't include a sorting example, but you can easily modify the Demo 2's View Model to sort its hierarchical data. Just do the following:
SampleTreeNodePM
's base constructor indicates if the View Model collections should use the same indices as the Domain Model collections or not. Change this value to false
.DesiredPosition
method override's return value is a boolean that indicates whether to sort the View Model collection or not. Change this value to true
.Following from the previous step, you now need to modify the Domain Model object, SampleTreeNode
, to implement IComparable<SampleTreeNode>
. The CompareTo
method need simply delegate the job to the Name
string property:
public int CompareTo( SampleTreeNode other )
{
return Name.CompareTo( other.Name );
}
Regarding updating the position "on the fly" as your question says, just call my library's HierarchicalPresentationModel.UpdatePosition
method after making the change.
You can also use the CollectionViewSource.GetDefaultView
with ListCollectionView
to do the sorting for you, tho you do have to set it for all the child collections as well. I use a linq query to flatten my list to find all the children and set the sorting.
foreach (var structure in Model.Structures.Flatten(t => t.SubItems))
{
var view = CollectionViewSource
.GetDefaultView(structure.SubItems) as ListCollectionView;
if (view != null)
{
view.CustomSort = (x,y) => string.Compare( x, y );
}
}
elsewhere
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> list, Func<T, IEnumerable<T>> subitems)
{
foreach (T child in list)
{
yield return child;
foreach (T other in Flatten(subitems(child), subitems))
{
yield return other;
}
}
}