Подтвердить что ты не робот

Сортировать ObservableCollection <string> через С#

У меня ниже ObservableCollection<string>. Мне нужно отсортировать это по алфавиту.

private ObservableCollection<string> _animals = new ObservableCollection<string>
{
    "Cat", "Dog", "Bear", "Lion", "Mouse",
    "Horse", "Rat", "Elephant", "Kangaroo", "Lizard", 
    "Snake", "Frog", "Fish", "Butterfly", "Human", 
    "Cow", "Bumble Bee"
};

Я пытался _animals.OrderByDescending. Но я не знаю, как правильно его использовать.

_animals.OrderByDescending(a => a.<what_is_here_?>);

Как я могу это сделать?

4b9b3361

Ответ 1

Вступление

В принципе, если необходимо отобразить отсортированную коллекцию, рассмотрите возможность использования класса CollectionViewSource: присвойте ("привязать") его свойство Source к исходной коллекции - экземпляр класса ObservableCollection<T>.

Идея состоит в том, что класс CollectionViewSource предоставляет экземпляр класса CollectionView. Это своего рода "проекция" исходной (исходной) коллекции, но с применением сортировки, фильтрации и т.д.

Рекомендации:

Live Shaping

WPF 4.5 представляет функцию "Live Shaping" для CollectionViewSource.

Рекомендации:

Решение

Если еще нужно отсортировать экземпляр класса ObservableCollection<T>, вот как это можно сделать. Сам класс ObservableCollection<T> не имеет метода сортировки. Но коллекция могла быть воссоздана для сортировки предметов:

// Animals property setter must raise "property changed" event to notify binding clients.
// See INotifyPropertyChanged interface for details.
Animals = new ObservableCollection<string>
    {
        "Cat", "Dog", "Bear", "Lion", "Mouse",
        "Horse", "Rat", "Elephant", "Kangaroo",
        "Lizard", "Snake", "Frog", "Fish",
        "Butterfly", "Human", "Cow", "Bumble Bee"
    };
...
Animals = new ObservableCollection<string>(Animals.OrderBy(i => i));

Дополнительные детали

Обратите внимание, что OrderBy() и OrderByDescending() (как другие методы расширения LINQ) не изменяют исходную коллекцию! Вместо этого они создают новую последовательность (то есть новый экземпляр класса, реализующий интерфейс IEnumerable<T>). Таким образом, необходимо воссоздать коллекцию.

Ответ 2

Я знаю, что это старый вопрос, но это первый результат Google для "сортировки наблюдаемой коллекции", так что я подумал, что стоит оставить мои два цента.

Путь

Я бы хотел создать List<> начиная с ObservableCollection<>, отсортировать его (с помощью метода Sort(), подробнее о msdn), а после сортировки List<> изменить порядок ObservableCollection<> с помощью Метод Move().

Код

public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison)
{
    var sortableList = new List<T>(collection);
    sortableList.Sort(comparison);

    for (int i = 0; i < sortableList.Count; i++)
    {
        collection.Move(collection.IndexOf(sortableList[i]), i);
    }
}

Тест

public void TestObservableCollectionSortExtension()
{
    var observableCollection = new ObservableCollection<int>();
    var maxValue = 10;

    // Populate the list in reverse mode [maxValue, maxValue-1, ..., 1, 0]
    for (int i = maxValue; i >= 0; i--)
    {
        observableCollection.Add(i);
    }

    // Assert the collection is in reverse mode
    for (int i = maxValue; i >= 0; i--)
    {
        Assert.AreEqual(i, observableCollection[maxValue - i]);
    }

    // Sort the observable collection
    observableCollection.Sort((a, b) => { return a.CompareTo(b); });

    // Assert elements have been sorted
    for (int i = 0; i < maxValue; i++)
    {
        Assert.AreEqual(i, observableCollection[i]);
    }
}

Заметки

Это просто подтверждение концепции, показывающее, как сортировать ObservableCollection<> без нарушения привязок к элементам. Алгоритм сортировки имеет пространство для улучшений и проверок (например, проверка индекса, как указано здесь).

Ответ 3

Я создал метод расширения для ObservableCollection

public static void MySort<TSource,TKey>(this ObservableCollection<TSource> observableCollection, Func<TSource, TKey> keySelector)
    {
        var a = observableCollection.OrderBy(keySelector).ToList();
        observableCollection.Clear();
        foreach(var b in a)
        {
            observableCollection.Add(b);
        }
    }

Кажется, что работает, и вам не нужно реализовывать IComparable

Ответ 4

Я посмотрел на них, я его отсортировал, а затем сломал привязку, как указано выше. Придумал это решение, хотя и проще, чем у большинства из вас, он, похоже, делает то, что я хочу,

public static ObservableCollection<string> OrderThoseGroups( ObservableCollection<string> orderThoseGroups)
    {
        ObservableCollection<string> temp;
        temp =  new ObservableCollection<string>(orderThoseGroups.OrderBy(p => p));
        orderThoseGroups.Clear();
        foreach (string j in temp) orderThoseGroups.Add(j);
        return orderThoseGroups;



    }

Ответ 5

Это ObservableCollection<T>, который автоматически сортирует себя при изменении, запускает сортировку только тогда, когда это необходимо, и вызывает только одно действие изменения коллекции перемещения.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

namespace ConsoleApp4
{
  using static Console;

  public class SortableObservableCollection<T> : ObservableCollection<T>
  {
    public Func<T, object> SortingSelector { get; set; }
    public bool Descending { get; set; }
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
      base.OnCollectionChanged(e);
      if (e.Action != NotifyCollectionChangedAction.Reset
         && e.Action != NotifyCollectionChangedAction.Move
         && SortingSelector != null)
      {                              
        var query = this
          .Select((item, index) => (Item: item, Index: index));
        query = Descending
          ? query.OrderBy(tuple => SortingSelector(tuple.Item))
          : query.OrderByDescending(tuple => SortingSelector(tuple.Item));

        var map = query.Select((tuple, index) => (OldIndex:tuple.Index, NewIndex:index))
         .Where(o => o.OldIndex != o.NewIndex);

        using (var enumerator = map.GetEnumerator())
          if (enumerator.MoveNext())
            Move(enumerator.Current.OldIndex, enumerator.Current.NewIndex);
      }
    }
  }


  //USAGE
  class Program
  {
    static void Main(string[] args)
    {
      var xx = new SortableObservableCollection<int>() { SortingSelector = i => i };
      xx.CollectionChanged += (sender, e) =>
       WriteLine($"action: {e.Action}, oldIndex:{e.OldStartingIndex},"
         + " newIndex:{e.NewStartingIndex}, newValue: {xx[e.NewStartingIndex]}");

      xx.Add(10);
      xx.Add(8);
      xx.Add(45);
      xx.Add(0);
      xx.Add(100);
      xx.Add(-800);
      xx.Add(4857);
      xx.Add(-1);

      foreach (var item in xx)
        Write($"{item}, ");
    }
  }
}

Вывод:

action: Add, oldIndex:-1, newIndex:0, newValue: 10
action: Add, oldIndex:-1, newIndex:1, newValue: 8
action: Move, oldIndex:1, newIndex:0, newValue: 8
action: Add, oldIndex:-1, newIndex:2, newValue: 45
action: Add, oldIndex:-1, newIndex:3, newValue: 0
action: Move, oldIndex:3, newIndex:0, newValue: 0
action: Add, oldIndex:-1, newIndex:4, newValue: 100
action: Add, oldIndex:-1, newIndex:5, newValue: -800
action: Move, oldIndex:5, newIndex:0, newValue: -800
action: Add, oldIndex:-1, newIndex:6, newValue: 4857
action: Add, oldIndex:-1, newIndex:7, newValue: -1
action: Move, oldIndex:7, newIndex:1, newValue: -1
-800, -1, 0, 8, 10, 45, 100, 4857,

Ответ 6

Аргумент OrderByDescending - это функция, возвращающая ключ для сортировки. В вашем случае ключ является самой строкой:

var result = _animals.OrderByDescending(a => a);

Если вы хотите отсортировать по длине, например, вы напишете:

var result = _animals.OrderByDescending(a => a.Length);

Ответ 7

_animals.OrderByDescending(a => a.<what_is_here_?>);

Если животные будут списком объектов Animal, вы можете использовать свойство для заказа списка.

public class Animal
{
    public int ID {get; set;}
    public string Name {get; set;}
    ...
}

ObservableCollection<Animal> animals = ...
animals = animals.OrderByDescending(a => a.Name);

Ответ 8

myObservableCollection.ToList().Sort((x, y) => x.Property.CompareTo(y.Property));

Ответ 9

/// <summary>
/// Sorts the collection.
/// </summary>
/// <typeparam name="T">The type of the elements of the collection.</typeparam>
/// <param name="collection">The collection to sort.</param>
/// <param name="comparison">The comparison used for sorting.</param>
public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison = null)
{
    var sortableList = new List<T>(collection);
    if (comparison == null)
        sortableList.Sort();
    else
        sortableList.Sort(comparison);

    for (var i = 0; i < sortableList.Count; i++)
    {
        var oldIndex = collection.IndexOf(sortableList[i]);
        var newIndex = i;
        if (oldIndex != newIndex)
            collection.Move(oldIndex, newIndex);
    }
}

Это решение основано на ответе Марко. У меня были проблемы с с его решением, и поэтому он улучшил его, вызвав только Move, если индекс действительно изменился. Это должно повысить производительность, а также устранить связанную проблему.

Ответ 10

Я сделал сортировку по определенному полю класса (расстояние).

public class RateInfo 
{
    public string begin { get; set; }
    public string end { get; set; }
    public string price { get; set; }
    public string comment { get; set; }
    public string phone { get; set; }
    public string ImagePath { get; set; }
    public string what { get; set; }
    public string distance { get; set; }
}    

public ObservableCollection<RateInfo> Phones { get; set; }

public List<RateInfo> LRate { get; set; }

public ObservableCollection<RateInfo> Phones { get; set; }

public List<RateInfo> LRate { get; set; }

......

foreach (var item in ph)
        {

            LRate.Add(new RateInfo { begin = item["begin"].ToString(), end = item["end"].ToString(), price = item["price"].ToString(), distance=kilom, ImagePath = "chel.png" });
        }

       LRate.Sort((x, y) => x.distance.CompareTo(y.distance));

        foreach (var item in LRate)
        {
            Phones.Add(item);
        }

Ответ 11

Этот метод расширения избавляет от необходимости сортировать весь список.

Вместо этого он вставляет каждый новый элемент на место.

Таким образом, список всегда остается отсортированным.

Оказывается, этот метод работает только тогда, когда многие другие методы не работают из-за отсутствия уведомлений при изменении коллекции. И это довольно быстро.

Использовать:

// Call on dispatcher.
ObservableCollection<MyClass> collectionView = new ObservableCollection<MyClass>();
var p1 = new MyClass() { Key = "A" }
var p2 = new MyClass() { Key = "Z" }
var p3 = new MyClass() { Key = "D" }
collectionView.InsertInPlace(p1, o => o.Key);
collectionView.InsertInPlace(p2, o => o.Key);
collectionView.InsertInPlace(p3, o => o.Key);
// The list will always remain ordered on the screen, e.g. "A, D, Z" .
// Insertion speed is Log(N) as it uses a binary search.

И метод расширения:

/// <summary>
/// Inserts an item into a list in the correct place, based on the provided key and key comparer. Use like OrderBy(o => o.PropertyWithKey).
/// </summary>
public static void InsertInPlace<TItem, TKey>(this ObservableCollection<TItem> collection, TItem itemToAdd, Func<TItem, TKey> keyGetter)
{
    int index = collection.ToList().BinarySearch(keyGetter(itemToAdd), Comparer<TKey>.Default, keyGetter);
    collection.Insert(index, itemToAdd);
}

И метод расширения двоичного поиска:

/// <summary>
/// Binary search.
/// </summary>
/// <returns>Index of item in collection.</returns> 
/// <notes>This version tops out at approximately 25% faster than the equivalent recursive version. This 25% speedup is for list
/// lengths more of than 1000 items, with less performance advantage for smaller lists.</notes>
public static int BinarySearch<TItem, TKey>(this IList<TItem> collection, TKey keyToFind, IComparer<TKey> comparer, Func<TItem, TKey> keyGetter)
{
    if (collection == null)
    {
        throw new ArgumentNullException(nameof(collection));
    }

    int lower = 0;
    int upper = collection.Count - 1;

    while (lower <= upper)
    {
        int middle = lower + (upper - lower) / 2;
        int comparisonResult = comparer.Compare(keyToFind, keyGetter.Invoke(collection[middle]));
        if (comparisonResult == 0)
        {
            return middle;
        }
        else if (comparisonResult < 0)
        {
            upper = middle - 1;
        }
        else
        {
            lower = middle + 1;
        }
    }

    // If we cannot find the item, return the item below it, so the new item will be inserted next.
    return lower;
}