Sorting ObservableCollection<> manually

2019-09-08 07:50发布

问题:

I have following ObservableCollection in my class, I am binding data to my listbox using that Collection in my Windows phone 7 application

public ObservableCollection<CustomClass> myList = new ObservableCollection<CustomClass>();

My Custom Class

public class CustomClass
{
public string Id { get; set; }        
public string Name { get; set; }        
public string EventName { get; set; }        
public string EventDate get
{
    return EventDate;
}
set
{
    if (value != null)
    {
        DateTime eventDate = DateTime.Parse(value);
        int today = DateTime.Now.Day;
        if (eventDate.Day <= today + 1 & eventDate.Day >= today - 2)
        {
            if (eventDate.Day == today)
            EventDate = "Today";
            else if (eventDate.Day == (today + 1))
            EventDate = "Tomorrow";
            else if (eventDate.Day == (today - 1))
            EventDate = "Yesterday";
            else if (eventDate.Day >= (today - 2))
            EventDate = "Just Passed";
        }
        else
        {
            EventDate = value;
        }
    }
}
}

Now i want to sort myList according to the data in the EventDate

The Data in the EventDate will be one of the following in all the cases

  1. Just Passed
  2. Yesterday
  3. Tomorrow
  4. Today
  5. Date //Format "MMM/dd"

Custom Collection must be sorted according to the above order only

i am getting data from different sources so sorting is not possible at the time of binding data into the collection

Is it possible??

回答1:

Since your CustomClass doesn't implement INotifyPropertyChange, I'm assuming you'll only have to sort at insert (when adding to the collection). So IMHO, the easiest thing to do (similiar to Randolf Rincón-Fadul's solution) is to subclass, then override the Add method.

public class ComparingObservableCollection<T> : ObservableCollection<T>
     where T : IComparable<T>
{

    protected override void InsertItem(int index, T item)
    {
        int i = 0;
        bool found = false;
        for (i = 0; i < Items.Count; i++)
        {
            if (item.CompareTo(Items[i]) < 0) {
                found = true;
                break;
            }
        }

        if (!found) i = Count;

        base.InsertItem(i, item);
    }
}

Then all you have to do is implement IComparable<CustomClass> on CustomClass like this:

public class CustomClass : IComparable<CustomClass>
{
public string Id { get; set; }        
public string Name { get; set; }        
public string EventName { get; set; }        
public string EventDate { get
{
    return EventDate;
}
set
{
    if (value != null)
    {
        DateTime eventDate = DateTime.Parse(value);
        int today = DateTime.Now.Day;
        if (eventDate.Day <= today + 1 & eventDate.Day >= today - 2)
        {
            if (eventDate.Day == today)
            EventDate = "Today";
            else if (eventDate.Day == (today + 1))
            EventDate = "Tomorrow";
            else if (eventDate.Day == (today - 1))
            EventDate = "Yesterday";
            else if (eventDate.Day >= (today - 2))
            EventDate = "Just Passed";
        }
        else
        {
            EventDate = value;
        }
    }
}
    private int Order { get {
       switch(EventDate) {
         case "Just Passed": return 1;
         case "Yesterday": return 2;
         case "Tomorrow": return 3;
         case "Today": return 4;
         default: return 5;
       }
    }
    }

    public int CompareTo(CustomClass other) {
       return this.Order.CompareTo(other.Order);
    }
}


回答2:

Taken a look here??

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5909dbcc-9a9f-4260-bc36-de4aa9bbd383/

A few decent answers towards the bottom.



回答3:

You can always subclass:

/// <summary>
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed and allows sorting.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
public class SortableObservableCollection<T> : ObservableCollection<T>
{
    /// <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 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));
        }
    }
}

And then sort using a lambda expression

((SortableObservableCollection<CustomClass>)MyList).Sort(s => s.EventDate);