code

관찰 가능한 컬렉션을 정렬하려면 어떻게 해야 합니까?

starcafe 2023. 4. 28. 21:12
반응형

관찰 가능한 컬렉션을 정렬하려면 어떻게 해야 합니까?

저는 다음과 같은 수업이 있습니다.

[DataContract]
public class Pair<TKey, TValue> : INotifyPropertyChanged, IDisposable
{
    public Pair(TKey key, TValue value)
    {
        Key = key;
        Value = value;
    }

    #region Properties
    [DataMember]
    public TKey Key
    {
        get
        { return m_key; }
        set
        {
            m_key = value;
            OnPropertyChanged("Key");
        }
    }
    [DataMember]
    public TValue Value
    {
        get { return m_value; }
        set
        {
            m_value = value;
            OnPropertyChanged("Value");
        }
    }
    #endregion

    #region Fields
    private TKey m_key;
    private TValue m_value;
    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    { }

    #endregion
}

내가 관찰 가능한 컬렉션에 넣은 것:

ObservableCollection<Pair<ushort, string>> my_collection = 
    new ObservableCollection<Pair<ushort, string>>();

my_collection.Add(new Pair(7, "aaa"));
my_collection.Add(new Pair(3, "xey"));
my_collection.Add(new Pair(6, "fty"));

Q: 키별로 정렬하려면 어떻게 해야 하나요?

이 간단한 연장은 저에게 아주 잘 어울렸습니다.난 단지 그것을 확실히 해야만 했습니다.MyObject이었다IComparable 가 에서 될 때MyObjects,CompareTo에 있는 방법.MyObject이 호출되며, 이는 내 논리 정렬 메서드를 호출합니다.여기에 나머지 답변의 모든 내용이 게시되어 있지는 않지만, 제가 필요로 하는 것은 바로 그것입니다.

static class Extensions
{
    public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable
    {
        List<T> sorted = collection.OrderBy(x => x).ToList();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

public class MyObject: IComparable
{
    public int CompareTo(object o)
    {
        MyObject a = this;
        MyObject b = (MyObject)o;
        return Utils.LogicalStringCompare(a.Title, b.Title);
    }

    public string Title;

}
  .
  .
  .
myCollection = new ObservableCollection<MyObject>();
//add stuff to collection
myCollection.Sort();

여기 있는 블로그 항목보다 더 나은 답변을 제공하는 관련 블로그 항목을 찾았습니다.

http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html

갱신하다

@romkyns가 주석에서 가리키는 ObservableSortedList는 자동으로 정렬 순서를 유지합니다.

항목을 정렬된 순서로 유지 관리하는 관찰 가능한 컬렉션을 구현합니다.특히 순서 변경을 초래하는 항목 속성의 변경은 올바르게 처리됩니다.

그러나 주의 또한 언급합니다.

관련된 인터페이스의 비교적 복잡성과 문서가 상대적으로 빈약하기 때문에 버그가 있을 수 있습니다(https://stackoverflow.com/a/5883947/33080) 참조).

다음과 같은 간단한 방법을 사용할 수 있습니다.

public static void Sort<TSource, TKey>(this Collection<TSource> source, Func<TSource, TKey> keySelector)
{
    List<TSource> sortedList = source.OrderBy(keySelector).ToList();
    source.Clear();
    foreach (var sortedItem in sortedList)
        source.Add(sortedItem);
}

다음과 같이 정렬할 수 있습니다.

_collection.Sort(i => i.Key);

관찰 가능한 개체를 정렬하고 정렬된 동일한 개체를 반환하는 작업은 확장 방법을 사용하여 수행할 수 있습니다.더 큰 컬렉션의 경우 컬렉션 변경 알림 수를 주의하십시오.

저는 (나팔 덕분에) 성능을 향상시키고 작성 시 여기에 다른 답변이 없는 중복 사항을 처리하기 위해 코드를 업데이트했습니다.관찰 가능한 항목은 왼쪽 정렬된 절반과 오른쪽 정렬되지 않은 절반으로 분할되며, 여기서 최소 항목(정렬된 목록에 있는 것처럼)은 정렬되지 않은 파티션에서 정렬된 파티션의 끝으로 이동됩니다.최악의 경우 O(n).기본적으로 선택 정렬(출력은 아래 참조).

public static void Sort<T>(this ObservableCollection<T> collection)
        where T : IComparable<T>, IEquatable<T>
    {
        List<T> sorted = collection.OrderBy(x => x).ToList();

        int ptr = 0;
        while (ptr < sorted.Count - 1)
        {
            if (!collection[ptr].Equals(sorted[ptr]))
            {
                int idx = search(collection, ptr+1, sorted[ptr]);
                collection.Move(idx, ptr);
            }
            
            ptr++;
        }
    }

    public static int search<T>(ObservableCollection<T> collection, int startIndex, T other)
            {
                for (int i = startIndex; i < collection.Count; i++)
                {
                    if (other.Equals(collection[i]))
                        return i;
                }
    
                return -1; // decide how to handle error case
            }

사용법: 관찰자와 함께 샘플(간단하게 유지하기 위해 사용자 클래스 사용)

    public class Person:IComparable<Person>,IEquatable<Person>
            { 
                public string Name { get; set; }
                public int Age { get; set; }
    
                public int CompareTo(Person other)
                {
                    if (this.Age == other.Age) return 0;
                    return this.Age.CompareTo(other.Age);
                }
    
                public override string ToString()
                {
                    return Name + " aged " + Age;
                }
    
                public bool Equals(Person other)
                {
                    if (this.Name.Equals(other.Name) && this.Age.Equals(other.Age)) return true;
                    return false;
                }
            }
    
          static void Main(string[] args)
            {
                Console.WriteLine("adding items...");
                var observable = new ObservableCollection<Person>()
                {
                    new Person {Name = "Katy", Age = 51},
                    new Person {Name = "Jack", Age = 12},
                    new Person {Name = "Bob", Age = 13},
                    new Person {Name = "Alice", Age = 39},
                    new Person {Name = "John", Age = 14},
                    new Person {Name = "Mary", Age = 41},
                    new Person {Name = "Jane", Age = 20},
                    new Person {Name = "Jim", Age = 39},
                    new Person {Name = "Sue", Age = 5},
                    new Person {Name = "Kim", Age = 19}
                };
    
                //what do observers see?
            
    
observable.CollectionChanged += (sender, e) =>
        {
            Console.WriteLine(
                e.OldItems[0] + " move from " + e.OldStartingIndex + " to " + e.NewStartingIndex);
            int i = 0;
            foreach (var person in sender as ObservableCollection<Person>)
            {
                if (i == e.NewStartingIndex)
                {
                    Console.Write("(" + (person as Person).Age + "),");
                }
                else
                {
                    Console.Write((person as Person).Age + ",");
                }
                
                i++;
            }

            Console.WriteLine();
        };

컬렉션이 피벗되는 방식을 보여주는 정렬 진행률 세부 정보:

Sue aged 5 move from 8 to 0
(5),51,12,13,39,14,41,20,39,19,
Jack aged 12 move from 2 to 1
5,(12),51,13,39,14,41,20,39,19,
Bob aged 13 move from 3 to 2
5,12,(13),51,39,14,41,20,39,19,
John aged 14 move from 5 to 3
5,12,13,(14),51,39,41,20,39,19,
Kim aged 19 move from 9 to 4
5,12,13,14,(19),51,39,41,20,39,
Jane aged 20 move from 8 to 5
5,12,13,14,19,(20),51,39,41,39,
Alice aged 39 move from 7 to 6
5,12,13,14,19,20,(39),51,41,39,
Jim aged 39 move from 9 to 7
5,12,13,14,19,20,39,(39),51,41,
Mary aged 41 move from 9 to 8
5,12,13,14,19,20,39,39,(41),51,

개인 클래스는 IComparable 및 IEqualable을 모두 구현합니다. 후자는 컬렉션에 대한 변경 사항을 최소화하여 제기되는 변경 알림의 수를 줄이는 데 사용됩니다.

  • 편집 새 복사본을 만들지 않고 동일한 컬렉션을 정렬합니다 *

관찰 가능한 컬렉션을 반환하려면 전화하십시오.*sorted에서 관찰 가능한 컬렉션으로예를 들어 OC*를 사용합니다.[본 구현][1].

orig answer - 새 컬렉션을 만듭니다 **** 아래의 doSort 메서드와 같이 linq를 사용할 수 있습니다.빠른 코드 스니펫: 생성

3:xey 6:fty 7:ty 7:ty

또는 컬렉션 자체에 확장 메서드를 사용할 수 있습니다.

var sortedOC = _collection.OrderBy(i => i.Key);

private void doSort()
{
    ObservableCollection<Pair<ushort, string>> _collection = 
        new ObservableCollection<Pair<ushort, string>>();

    _collection.Add(new Pair<ushort,string>(7,"aaa"));
    _collection.Add(new Pair<ushort, string>(3, "xey"));
    _collection.Add(new Pair<ushort, string>(6, "fty"));

    var sortedOC = from item in _collection
                   orderby item.Key
                   select item;

    foreach (var i in sortedOC)
    {
        Debug.WriteLine(i);
    }

}

public class Pair<TKey, TValue>
{
    private TKey _key;

    public TKey Key
    {
        get { return _key; }
        set { _key = value; }
    }
    private TValue _value;

    public TValue Value
    {
        get { return _value; }
        set { _value = value; }
    }
    
    public Pair(TKey key, TValue value)
    {
        _key = key;
        _value = value;

    }

    public override string ToString()
    {
        return this.Key + ":" + this.Value;
    }
}

WPF는 다음을 사용하여 즉시 실시간 정렬 기능을 제공합니다.ListCollectionView수업...

public ObservableCollection<string> MyStrings { get; set; }
private ListCollectionView _listCollectionView;
private void InitializeCollection()
{
    MyStrings = new ObservableCollection<string>();
    _listCollectionView = CollectionViewSource.GetDefaultView(MyStrings) 
              as ListCollectionView;
    if (_listCollectionView != null)
    {
        _listCollectionView.IsLiveSorting = true;
        _listCollectionView.CustomSort = new 
                CaseInsensitiveComparer(CultureInfo.InvariantCulture);
    }
}

이 초기화가 완료되면 더 이상 할 일이 없습니다.수동 정렬보다 장점은 ListCollectionView가 개발자에게 투명한 방식으로 모든 무거운 작업을 수행한다는 것입니다.새 항목은 올바른 정렬 순서로 자동 배치됩니다.에서 된 모든 클래스IComparer사용자 지정 정렬 속성에 적합합니다.

설명서 및 기타 기능은 목록 모음 보기를 참조하십시오.

위의 "Richie" 블로그에 있는 버블 정렬 확장 방법 접근법이 마음에 들었지만, 반드시 전체 객체를 비교하여 정렬하고 싶지는 않습니다.개체의 특정 속성을 정렬하고 싶을 때가 많습니다.그래서 OrderBy처럼 키 선택기를 사용할 수 있도록 수정하여 정렬할 속성을 선택할 수 있습니다.

    public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector)
    {
        if (source == null) return;

        Comparer<TKey> comparer = Comparer<TKey>.Default;

        for (int i = source.Count - 1; i >= 0; i--)
        {
            for (int j = 1; j <= i; j++)
            {
                TSource o1 = source[j - 1];
                TSource o2 = source[j];
                if (comparer.Compare(keySelector(o1), keySelector(o2)) > 0)
                {
                    source.Remove(o1);
                    source.Insert(j, o1);
                }
            }
        }
    }

OrderBy를 호출하는 것과 동일한 방법으로 호출하면 새 컬렉션을 반환하는 대신 기존 ObservableCollection 인스턴스가 정렬됩니다.

ObservableCollection<Person> people = new ObservableCollection<Person>();
...

people.Sort(p => p.FirstName);

@NielW의 대답은 실제 인플레이스 정렬을 위한 방법입니다.사용하지 않아도 되는 약간 변경된 솔루션을 추가하고 싶었습니다.IComparable:

static class Extensions
{
    public static void Sort<TSource, TKey>(this ObservableCollection<TSource> collection, Func<TSource, TKey> keySelector)
    {
        List<TSource> sorted = collection.OrderBy(keySelector).ToList();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

이제 대부분의 LINQ 방법처럼 호출할 수 있습니다.

myObservableCollection.Sort(o => o.MyProperty);

Neil W의 답변에 추가하고 싶습니다.순서와 유사한 방법을 통합합니다.이 메서드를 확장으로 추가합니다.

public static void Sort<T>(this ObservableCollection<T> collection, Func<T,T> keySelector) where T : IComparable
{
    List<T> sorted = collection.OrderBy(keySelector).ToList();
    for (int i = 0; i < sorted.Count(); i++)
        collection.Move(collection.IndexOf(sorted[i]), i);
}

다음과 같은 용도:

myCollection = new ObservableCollection<MyObject>();

//Sorts in place, on a specific Func<T,T>
myCollection.Sort(x => x.ID);

변형은 선택 정렬 알고리즘을 사용하여 집합을 제자리에 정렬하는 것입니다.메소드를 사용하여 요소가 제자리로 이동됩니다.한 번 움직일 때마다 이벤트가 시작됩니다.NotifyCollectionChangedAction.Move(및 속성 이름 포함)Item[]).

이 알고리즘에는 몇 가지 좋은 속성이 있습니다.

  • 알고리즘은 안정적인 정렬로 구현될 수 있습니다.
  • 의 수( " " " " " " " " " " "CollectionChanged이벤트 발생)는 삽입 정렬 및 버블 정렬과 같은 다른 유사한 알고리즘보다 거의 항상 작습니다.

알고리즘은 매우 간단합니다.가장 작은 요소를 찾기 위해 컬렉션을 반복한 다음 컬렉션의 시작 부분으로 이동합니다.이 프로세스는 두 번째 요소부터 시작하여 모든 요소가 제자리로 이동될 때까지 반복됩니다.알고리즘은 매우 효율적이지는 않지만 사용자 인터페이스에 표시되는 모든 것에 대해서는 문제가 되지 않습니다.그러나 이동 작업의 수 측면에서는 상당히 효율적입니다.

다음은 단순성을 위해 요소가 구현해야 하는 확장 방법입니다.IComparable<T>으로는 다옵은다사다니용합음을션을 사용하는 .IComparer<T> 는또.Func<T, T, Int32>.

public static class ObservableCollectionExtensions {

  public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T> {
    if (collection == null)
      throw new ArgumentNullException("collection");

    for (var startIndex = 0; startIndex < collection.Count - 1; startIndex += 1) {
      var indexOfSmallestItem = startIndex;
      for (var i = startIndex + 1; i < collection.Count; i += 1)
        if (collection[i].CompareTo(collection[indexOfSmallestItem]) < 0)
          indexOfSmallestItem = i;
      if (indexOfSmallestItem != startIndex)
        collection.Move(indexOfSmallestItem, startIndex);
    }
  }

}

컬렉션 정렬은 확장 메서드를 호출하는 것만으로 이루어집니다.

var collection = new ObservableCollection<String>(...);
collection.Sort();

xr280xr 응답에 대한 확장 방법을 조금 개선하기 위해 정렬이 내림차순인지 여부를 결정하는 옵션 bool 매개 변수를 추가했습니다.저는 그 답변에 대한 코멘트에 Carlos P가 제안한 내용도 포함했습니다.아래를 참조하십시오.

public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector, bool desc = false)
    {
        if (source == null) return;

        Comparer<TKey> comparer = Comparer<TKey>.Default;

        for (int i = source.Count - 1; i >= 0; i--)
        {
            for (int j = 1; j <= i; j++)
            {
                TSource o1 = source[j - 1];
                TSource o2 = source[j];
                int comparison = comparer.Compare(keySelector(o1), keySelector(o2));
                if (desc && comparison < 0)
                    source.Move(j, j - 1);
                else if (!desc && comparison > 0)
                    source.Move(j - 1, j);
            }
        }
    }

수집품을 항상 분류해 두어야 합니까?쌍을 검색할 때 항상 정렬해야 합니까? 아니면 몇 번만(아마 프레젠테이션용으로만) 정렬해야 합니까?당신은 당신의 컬렉션이 얼마나 클 것으로 예상합니까?사용할 마녀 방법을 결정하는 데 도움이 될 수 있는 많은 요인이 있습니다.

컬렉션을 항상 정렬해야 하는 경우 요소를 삽입하거나 삭제하고 삽입 속도가 문제가 되지 않더라도 다음과 같은 작업을 수행해야 합니다.SortedObservableCollection@Gerry Schenck가 언급했거나 이 구현을 확인하십시오.

컬렉션을 몇 번만 정렬해야 하는 경우 다음을 사용합니다.

my_collection.OrderBy(p => p.Key);

이렇게 하면 컬렉션을 정렬하는 데 시간이 좀 걸리지만, 그래도 컬렉션을 사용하는 방법에 따라 가장 좋은 해결책이 될 수 있습니다.

저의 현재 답변은 이미 가장 많은 표를 얻었지만, 저는 이것을 하는 더 나은, 더 현대적인 방법을 찾았습니다.

class MyObject 
{
      public int id { get; set; }
      public string title { get; set; }
}

ObservableCollection<MyObject> myCollection = new ObservableCollection<MyObject>();

//add stuff to collection
// .
// .
// .

myCollection = new ObservableCollection<MyObject>(
    myCollection.OrderBy(n => n.title, Comparer<string>.Create(
    (x, y) => (Utils.Utils.LogicalStringCompare(x, y)))));

이것은 저에게 효과가 있었고, 오래 전에 어딘가에서 발견되었습니다.

// SortableObservableCollection
public class SortableObservableCollection<T> : ObservableCollection<T>
    {
        public SortableObservableCollection(List<T> list)
            : base(list)
        {
        }

        public SortableObservableCollection()
        {
        }

        public void Sort<TKey>(Func<T, TKey> keySelector, System.ComponentModel.ListSortDirection direction)
        {
            switch (direction)
            {
                case System.ComponentModel.ListSortDirection.Ascending:
                    {
                        ApplySort(Items.OrderBy(keySelector));
                        break;
                    }
                case System.ComponentModel.ListSortDirection.Descending:
                    {
                        ApplySort(Items.OrderByDescending(keySelector));
                        break;
                    }
            }
        }

        public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
        {
            ApplySort(Items.OrderBy(keySelector, comparer));
        }

        private void ApplySort(IEnumerable<T> sortedItems)
        {
            var sortedItemsList = sortedItems.ToList();

            foreach (var item in sortedItemsList)
            {
                Move(IndexOf(item), sortedItemsList.IndexOf(item));
            }
        }
    }

용도:

MySortableCollection.Sort(x => x, System.ComponentModel.ListSortDirection.Ascending);

클래스 SortedObservableCollection은 유한래서에서 합니다.ObservableCollection을 구현합니다.IComparable<Pair<ushort, string>>.

한 가지 방법은 목록으로 변환한 다음 Sort()를 호출하여 비교 대리자를 제공하는 것입니다.예를 들어:-

(테스트되지 않음)

my_collection.ToList().Sort((left, right) => left == right ? 0 : (left > right ? -1 : 1));

뭐라고요? 간단히 답변을 드리겠습니다. 여기에는 다른 구현과 약간 비슷하지만, 다음과 같은 사용자가 추가됩니다.

(테스트를 거의 받지 못했습니다, 제가 부끄럽지 않기를 바랍니다)

먼저 몇 가지 목표를 말씀드리겠습니다(제 가정).

정렬해야 합니다.ObservableCollection<T>알림을 유지 관리하는 등의 작업을 수행할 수 있습니다.

심하게 비효율적이어서는 안 됩니다(즉, 표준 "좋은" 정렬 효율에 가까운 ).

public static class Ext
{
    public static void Sort<T>(this ObservableCollection<T> src)
        where T : IComparable<T>
    {
        // Some preliminary safety checks
        if(src == null) throw new ArgumentNullException("src");
        if(!src.Any()) return;

        // N for the select,
        // + ~ N log N, assuming "smart" sort implementation on the OrderBy
        // Total: N log N + N (est)
        var indexedPairs = src
            .Select((item,i) => Tuple.Create(i, item))
            .OrderBy(tup => tup.Item2);
        // N for another select
        var postIndexedPairs = indexedPairs
            .Select((item,i) => Tuple.Create(i, item.Item1, item.Item2));
        // N for a loop over every element
        var pairEnum = postIndexedPairs.GetEnumerator();
        pairEnum.MoveNext();
        for(int idx = 0; idx < src.Count; idx++, pairEnum.MoveNext())
        {
            src.RemoveAt(pairEnum.Current.Item1);
            src.Insert(idx, pairEnum.Current.Item3);            
        }
        // (very roughly) Estimated Complexity: 
        // N log N + N + N + N
        // == N log N + 3N
    }
}

제 경우에는 이 대답들 중 어떤 것도 통하지 않았습니다.바인딩을 잘못해서인지, 아니면 너무 많은 추가 코딩이 필요해서인지, 아니면 그냥 답이 깨졌습니다.그래서 제가 생각했던 또 다른 더 간단한 답이 있습니다.코드가 훨씬 적으며 추가 this.sort 유형의 메서드와 함께 동일한 관측 가능한 컬렉션으로 남아 있습니다.이런 식으로 하면 안 되는 이유가 있다면 알려주십시오(효율성 등).

public class ScoutItems : ObservableCollection<ScoutItem>
{
    public void Sort(SortDirection _sDir, string _sItem)
    {
             //TODO: Add logic to look at _sItem and decide what property to sort on
            IEnumerable<ScoutItem> si_enum = this.AsEnumerable();

            if (_sDir == SortDirection.Ascending)
            {
                si_enum = si_enum.OrderBy(p => p.UPC).AsEnumerable();
            } else
            {
                si_enum = si_enum.OrderByDescending(p => p.UPC).AsEnumerable();
            }

            foreach (ScoutItem si in si_enum)
            {
                int _OldIndex = this.IndexOf(si);
                int _NewIndex = si_enum.ToList().IndexOf(si);
                this.MoveItem(_OldIndex, _NewIndex);
            }
      }
}

...스카웃 아이템이 공개 수업인 곳.훨씬 더 단순해 보였습니다.추가 이점: 실제로 작동하며 바인딩을 방해하거나 새 컬렉션을 반환하지 않습니다.

알겠습니다. XAML에서 ObservableSortedList를 사용하는 데 문제가 있었기 때문에 Sorting ObservableCollection을 만들었습니다.ObservableCollection에서 상속되므로 XAML과 함께 작동하며 98% 코드 적용 범위까지 유닛 테스트를 수행했습니다.나는 그것을 내 앱에서 사용해봤지만, 나는 그것이 버그가 없다고 약속하지 않을 것입니다.얼마든지 기부하세요.다음은 샘플 코드 사용 방법입니다.

var collection = new SortingObservableCollection<MyViewModel, int>(Comparer<int>.Default, model => model.IntPropertyToSortOn);

collection.Add(new MyViewModel(3));
collection.Add(new MyViewModel(1));
collection.Add(new MyViewModel(2));
// At this point, the order is 1, 2, 3
collection[0].IntPropertyToSortOn = 4; // As long as IntPropertyToSortOn uses INotifyPropertyChanged, this will cause the collection to resort correctly

PCL이므로 Windows Store, Windows Phone 및 에서 작동해야 합니다.NET 4.5.1.

OC 확장 기능은 다음과 같습니다.

    /// <summary>
    /// Synches the collection items to the target collection items.
    /// This does not observe sort order.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">The items.</param>
    /// <param name="updatedCollection">The updated collection.</param>
    public static void SynchCollection<T>(this IList<T> source, IEnumerable<T> updatedCollection)
    {
        // Evaluate
        if (updatedCollection == null) return;

        // Make a list
        var collectionArray = updatedCollection.ToArray();

        // Remove items from FilteredViewItems not in list
        source.RemoveRange(source.Except(collectionArray));

        // Add items not in FilteredViewItems that are in list
        source.AddRange(collectionArray.Except(source));
    }

    /// <summary>
    /// Synches the collection items to the target collection items.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">The source.</param>
    /// <param name="updatedCollection">The updated collection.</param>
    /// <param name="canSort">if set to <c>true</c> [can sort].</param>
    public static void SynchCollection<T>(this ObservableCollection<T> source,
        IList<T> updatedCollection, bool canSort = false)
    {
        // Synch collection
        SynchCollection(source, updatedCollection.AsEnumerable());

        // Sort collection
        if (!canSort) return;

        // Update indexes as needed
        for (var i = 0; i < updatedCollection.Count; i++)
        {
            // Index of new location
            var index = source.IndexOf(updatedCollection[i]);
            if (index == i) continue;

            // Move item to new index if it has changed.
            source.Move(index, i);
        }
    }

저는 하나가 아니라 여러 가지로 분류할 수 있어야 했습니다.이 답변은 일부 다른 답변을 기반으로 하지만 더 복잡한 정렬이 가능합니다.

static class Extensions
{
    public static void Sort<T, TKey>(this ObservableCollection<T> collection, Func<ObservableCollection<T>, TKey> sort)
    {
        var sorted = (sort.Invoke(collection) as IOrderedEnumerable<T>).ToArray();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

사용할 때는 일련의 OrderBy/ThenBy 호출을 전달합니다.다음과 같이:

Children.Sort(col => col.OrderByDescending(xx => xx.ItemType == "drive")
                    .ThenByDescending(xx => xx.ItemType == "folder")
                    .ThenBy(xx => xx.Path));

저는 다른 해결책들로부터 많은 것을 배웠지만, 몇 가지 문제점들을 발견했습니다.첫째, 일부는 큰 목록에 대해 매우 느린 경향이 있는 IndexOf에 의존합니다.둘째, 내 ObservableCollection에는 EF 엔티티가 있으며 Remove를 사용하면 일부 외부 키 속성이 손상되는 것처럼 보였습니다.아마 제가 뭔가 잘못하고 있는 것 같아요.

그럼에도 불구하고 Remove/Insert(제거/삽입) 대신 Move(이동)를 사용할 수 있지만 성능 수정에 몇 가지 문제가 발생합니다.

성능 문제를 해결하기 위해 정렬된 값의 인덱스로 사전을 만듭니다.사전을 최신 상태로 유지하고 엔티티 속성을 보존하려면 다른 솔루션에 구현된 것처럼 두 개의 이동 대신 두 개의 이동으로 구현된 스왑을 사용합니다.

한 번만 이동하면 요소의 인덱스가 위치 간에 이동하므로 인덱스 오브 사전이 무효화됩니다.스왑 구현을 위한 두 번째 이동을 추가하면 위치가 복원됩니다.

public static void Sort<TSource, TKey>(this ObservableCollection<TSource> collection, Func<TSource, TKey> keySelector)
{
    List<TSource> sorted = collection.OrderBy(keySelector).ToList();
    Dictionary<TSource, int> indexOf = new Dictionary<TSource, int>();

    for (int i = 0; i < sorted.Count; i++)
        indexOf[sorted[i]] = i;

    int idx = 0;
    while (idx < sorted.Count)
        if (!collection[idx].Equals(sorted[idx])) {
            int newIdx = indexOf[collection[idx]]; // where should current item go?
            collection.Move(newIdx, idx); // move whatever's there to current location
            collection.Move(idx + 1, newIdx); // move current item to proper location
        }
        else {
            idx++;
        }
}
var collection = new ObservableCollection<int>();

collection.Add(7);
collection.Add(4);
collection.Add(12);
collection.Add(1);
collection.Add(20);

// ascending
collection = new ObservableCollection<int>(collection.OrderBy(a => a));

// descending
collection = new ObservableCollection<int>(collection.OrderByDescending(a => a));

언급URL : https://stackoverflow.com/questions/1945461/how-do-i-sort-an-observable-collection

반응형