Mac*_*iek 93 .net c# sorting wpf observablecollection
我有以下课程:
[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
}
Run Code Online (Sandbox Code Playgroud)
我把它放在一个ObservableCollection中:
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"));
Run Code Online (Sandbox Code Playgroud)
问:我如何按键排序?
Nie*_*elW 79
这个简单的扩展对我来说很漂亮.我只是要确保那MyObject是IComparable.在可观察集合上调用sort方法时,将调用on 方法MyObjects,该CompareTo方法MyObject调用我的Logical Sort方法.虽然这里没有其他答案的所有花里胡哨,但这正是我所需要的.
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();
Run Code Online (Sandbox Code Playgroud)
Eri*_* J. 38
我知道这个问题已经过时了,但是谷歌搜索时发现了一个相关的博客条目,提供了比这里更好的答案:
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
UPDATE
@romkyns在注释中指出的ObservableSortedList自动维护排序顺序.
实现一个可观察的集合,该集合按排序顺序维护其项目.特别是,正确处理导致订单更改的项属性的更改.
但是请注意这句话
由于涉及的界面相对复杂,文档相对较差,可能会出错(参见/sf/answers/411876321/).
Jai*_*der 24
你可以使用这个简单的方法:
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);
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样排序:
_collection.Sort(i => i.Key);
Run Code Online (Sandbox Code Playgroud)
更多细节:http://jaider.net/2011-05-04/sort-a-observablecollection/
And*_*rew 20
OP编辑:正如许多人已正确指出原始答案不会返回相同的集合,(最初更侧重于排序Q的字典部分).请参阅底部的编辑,其中我解决了可观察集合的排序问题.原来离开这里仍然收到投票
您可以使用linq作为下面的doSort方法说明.一个快速的代码片段:产生
3:xey 6:fty 7:aaa
或者,您可以对集合本身使用扩展方法
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;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
要返回ObservableCollection,请使用例如此实现在sortedOC上调用.ToObservableCollection .
OP EDIT 可以使用扩展方法对可观察对象进行排序并返回相同的对象.对于较大的收藏品,请注意收集更改通知的数量,例如
public static void Sort<T>(this ObservableCollection<T> observable) where T : IComparable<T>, IEquatable<T>
{
List<T> sorted = observable.OrderBy(x => x).ToList();
int ptr = 0;
while (ptr < sorted.Count)
{
if (!observable[ptr].Equals(sorted[ptr]))
{
T t = observable[ptr];
observable.RemoveAt(ptr);
observable.Insert(sorted.IndexOf(t), t);
}
else
{
ptr++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:使用观察者的示例(使用Person类来保持简单)
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 = "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 = 15 },
new Person { Name = "Kim", Age = 19 }
};
//what do observers see?
observable.CollectionChanged += (o, e) => {
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
Console.WriteLine("removed {0} at index {1}", item, e.OldStartingIndex);
}
}
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
Console.WriteLine("added {0} at index {1}", item, e.NewStartingIndex);
}
}};
Console.WriteLine("\nsorting items...");
observable.Sort();
};
Run Code Online (Sandbox Code Playgroud)
上述输出:
删除Katy年龄51岁,指数0
加入Katy年龄51岁,指数8年
去除Mary年龄41岁,指数3
年级Mary年龄41岁,指数7年
删除Jane年龄20岁,指数3
添加Jane年龄20岁,指数5年
移除Jim年龄39岁在指数3处,
吉姆在指数6处追踪了39
岁.在指数4处,
简20岁的简添加了简20岁,在指数5处
Person类实现IComparable和IEquatable,后者用于最小化对集合的更改,以减少引发的更改通知的数量
Gay*_*Fow 18
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);
}
}
Run Code Online (Sandbox Code Playgroud)
一旦完成初始化,就没有更多的事情可做了.被动排序的优势在于ListCollectionView以对开发人员透明的方式完成所有繁重工作.新项目将按正确的排序顺序自动放置.任何派生自IComparerT的类都适用于自定义排序属性.
有关文档和其他功能,请参阅ListCollectionView.
xr2*_*0xr 15
我喜欢上面"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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用与调用OrderBy相同的方式调用它,除非它将对ObservableCollection的现有实例进行排序,而不是返回新的集合:
ObservableCollection<Person> people = new ObservableCollection<Person>();
...
people.Sort(p => p.FirstName);
Run Code Online (Sandbox Code Playgroud)
对于真正的就地排序,@ 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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以像大多数LINQ方法一样调用它:
myObservableCollection.Sort(o => o.MyProperty);
Run Code Online (Sandbox Code Playgroud)
您可以使用选择排序算法对集合进行排序.使用该Move方法将元素移动到位.每次移动都将CollectionChanged使用NotifyCollectionChangedAction.Move(以及PropertyChanged属性名称Item[])触发事件.
这个算法有一些很好的属性:
CollectionChanged触发的事件)几乎总是小于插入排序和冒泡排序等其他类似算法.算法很简单.迭代该集合以找到最小元素,然后将其移动到集合的开头.从第二个元素开始重复该过程,依此类推,直到所有元素都移动到位.该算法效率不高,但对于您要在用户界面中显示的任何内容,它都无关紧要.但是,就移动操作的数量而言,它非常有效.
这是一种扩展方法,为简单起见,要求元素实现IComparable<T>.其他选项使用a IComparer<T>或a 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
对集合进行排序只需调用扩展方法:
var collection = new ObservableCollection<String>(...);
collection.Sort();
Run Code Online (Sandbox Code Playgroud)
我想加入NeilW的回答.合并一个类似于orderby的方法.将此方法添加为扩展名:
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);
}
Run Code Online (Sandbox Code Playgroud)
并使用如下:
myCollection = new ObservableCollection<MyObject>();
//Sorts in place, on a specific Func<T,T>
myCollection.Sort(x => x.ID);
Run Code Online (Sandbox Code Playgroud)