how to sort ObservableCollection

前端 未结 5 670
轮回少年
轮回少年 2020-12-08 06:00

I have a an ObservableCollection and a WPF UserControl is Databound to it. The Control is a graph that shows a vertical bar for each item of type BarData in the ObservableCo

5条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-08 06:36

    The problem with sorting an ObservableCollection is that every time you change the collection, an event will get fired off. So for a sort that is removing items from one position and adding them to another, you will end up having a ton of events firing.

    I think you're best bet is to just insert the stuff into the ObservableCollection in the proper order to begin with. Removing items from the collection won't effect ordering. I whipped up a quick extension method to illustrate

        public static void InsertSorted(this ObservableCollection collection, T item, Comparison comparison)
        {
            if (collection.Count == 0)
                collection.Add(item);
            else
            {
                bool last = true;
                for (int i = 0; i < collection.Count; i++)
                {
                    int result = comparison.Invoke(collection[i], item);
                    if (result >= 1)
                    {
                        collection.Insert(i, item);
                        last = false;
                        break;
                    }
                }
                if (last)
                    collection.Add(item);
            }
        }
    

    So if you were to use strings (for instance), the code would look like this

            ObservableCollection strs = new ObservableCollection();
            Comparison comparison = new Comparison((s1, s2) => { return String.Compare(s1, s2); });
            strs.InsertSorted("Mark", comparison);
            strs.InsertSorted("Tim", comparison);
            strs.InsertSorted("Joe", comparison);
            strs.InsertSorted("Al", comparison);
    

    Edit

    You can keep the calls identical if you extend the ObservableCollection and supply your own insert/add methods. Something like this:

    public class BarDataCollection : ObservableCollection
    {
        private Comparison _comparison = new Comparison((bd1, bd2) => { return DateTime.Compare(bd1.StartDate, bd2.StartDate); });
    
        public new void Insert(int index, BarData item)
        {
            InternalInsert(item);
        }
    
        protected override void InsertItem(int index, BarData item)
        {
            InternalInsert(item);
        }
    
        public new void Add(BarData item)
        {
            InternalInsert(item);
        }
    
        private void InternalInsert(BarData item)
        {
            if (Items.Count == 0)
                Items.Add(item);
            else
            {
                bool last = true;
                for (int i = 0; i < Items.Count; i++)
                {
                    int result = _comparison.Invoke(Items[i], item);
                    if (result >= 1)
                    {
                        Items.Insert(i, item);
                        last = false;
                        break;
                    }
                }
                if (last)
                    Items.Add(item);
            }
        }
    }
    

    The insert index is ignored.

            BarData db1 = new BarData(DateTime.Now.AddDays(-1));
            BarData db2 = new BarData(DateTime.Now.AddDays(-2));
            BarData db3 = new BarData(DateTime.Now.AddDays(1));
            BarData db4 = new BarData(DateTime.Now);
            BarDataCollection bdc = new BarDataCollection();
            bdc.Add(db1);
            bdc.Insert(100, db2);
            bdc.Insert(1, db3);
            bdc.Add(db4);
    

提交回复
热议问题