通过 C# 对 ObservableCollection<string> 进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19112922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 14:08:08  来源:igfitidea点击:

Sort ObservableCollection<string> through C#

c#sortingobservablecollection

提问by Bishan

I have below ObservableCollection<string>. I need to sortthis alphabetically.

我有以下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"
};

I tried _animals.OrderByDescending. But I don't know how to use it correctly.

我试过了_animals.OrderByDescending。但我不知道如何正确使用它。

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

How can I do this?

我怎样才能做到这一点?

采纳答案by Sergey Brunov

Introduction

介绍

Basically, if there is a need to display a sorted collection, please consider using the CollectionViewSourceclass: assign ("bind") its Sourceproperty to the source collection — an instance of the ObservableCollection<T>class.

基本上,如果需要显示排序集合,请考虑使用CollectionViewSource类:将其Source属性分配(“绑定”)到源集合——ObservableCollection<T>类的一个实例。

The idea is that CollectionViewSourceclass provides an instance of the CollectionViewclass. This is kind of "projection" of the original (source) collection, but with applied sorting, filtering, etc.

这个想法是,CollectionViewSource类提供的实例CollectionView。这是原始(源)集合的一种“投影”,但应用了排序、过滤等。

References:

参考:

Live Shaping

实时整形

WPF 4.5 introduces "Live Shaping" feature for CollectionViewSource.

WPF 4.5 为CollectionViewSource.

References:

参考:

Solution

解决方案

If there still a need to sort an instance of the ObservableCollection<T>class, here is how it can be done. The ObservableCollection<T>class itself does not have sort method. But, the collection could be re-created to have items sorted:

如果仍然需要对类的实例进行排序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));

Additional details

额外细节

Please note that OrderBy()and OrderByDescending()methods (as other LINQ–extension methods) do not modifythe source collection! They instead create a new sequence(i.e. a new instance of the class that implements IEnumerable<T>interface). Thus, it is necessary to re-create the collection.

请注意OrderBy()OrderByDescending()方法(与其他 LINQ 扩展方法一样)不会修改源集合!相反,它们创建了一个新序列(即实现IEnumerable<T>接口的类的新实例)。因此,有必要重新创建集合。

回答by manji

The argument to OrderByDescendingis a function returning a key to sort with. In your case, the key is the string itself:

to 的参数OrderByDescending是一个返回要排序的键的函数。在您的情况下,关键是字符串本身:

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

If you wanted to sort by length for example, you'll write:

例如,如果你想按长度排序,你会写:

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

回答by Bram Van Strydonck

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

If animals would be a list of object Animal, you could use a property to order the list.

如果动物是对象 Animal 的列表,您可以使用属性来对列表进行排序。

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

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

回答by Marco

I know this is an old question, but is the first google result for "sort observablecollection" so thought it worth to leave my two cent.

我知道这是一个老问题,但它是“排序可观察集合”的第一个谷歌结果,所以我认为值得留下我的两分钱。

The way

道路

The way I would go is to build a List<>starting from the ObservableCollection<>, sort it (through its Sort()method, more on msdn) and when the List<>has been sorted, reorder the ObservableCollection<>with the Move()method.

我要走的方法是List<>从 开始ObservableCollection<>,对其进行排序(通过其Sort()方法,更多关于 msdn),并在对List<>进行排序后,ObservableCollection<>使用该Move()方法重新排序。

The code

编码

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);
    }
}

The test

考试

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]);
    }
}

Notes

笔记

This is just a proof of concept, showing how to sort an ObservableCollection<>without breaking the bindings on items.The sort algorithm has room for improvements and validations (like index checking as pointed out here).

这仅仅是一个概念验证,展示如何排序的ObservableCollection<>,而不打破items.The排序算法的绑定有改进的空间和验证(如索引检查为指出,在这里)。

回答by John Leone

I looked at these, I was getting it sorted, and then it broke the binding, as above. Came up with this solution, though simpler than most of yours, it appears to do what I want to,,,

我看着这些,我正在整理它,然后它打破了绑定,如上所述。想出了这个解决方案,虽然比你的大多数解决方案简单,但它似乎可以做我想做的,,,

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;



    }

回答by Tim Pohlmann

/// <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);
    }
}

This solution is based on Marco's answer. I had some problemswith his solution and therefore improved it by only calling Moveif the index actually changed. This should improve performance and also fix the linked issue.

此解决方案基于Marco 的回答。我对他的解决方案有一些问题,因此仅Move在索引实际更改时才调用来改进它。这应该可以提高性能并解决相关问题。

回答by Lance

I created an extension method to the ObservableCollection

我为 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);
        }
    }

It seems to work and you don't need to implement IComparable

它似乎工作,你不需要实现 IComparable

回答by SabariMurugan Sivakumar

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

回答by Shimmy Weitzhandler

This is an ObservableCollection<T>, that automatically sorts itself upon a change, triggers a sort only when necessary, and only triggers a single move collection change action.

这是一个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 (SortingSelector == null 
          || e.Action == NotifyCollectionChangedAction.Remove
          || e.Action == NotifyCollectionChangedAction.Reset)
        return;

      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}, ");
    }
  }
}

Output:

输出:

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,

回答by Kairat Koibagarov

I did a sort on a certain class field (distance).

我对某个类字段(距离)进行了排序。

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);
        }