Sou*_*asu 16 sorting wpf observablecollection icollectionview
我有一个ObservableCollection和一个WPF UserControl是Databound.Control是一个图表,显示ObservableCollection中每个BarData类型项的垂直条.
ObservableCollection<BarData>
class BarData
{
public DateTime StartDate {get; set;}
public double MoneySpent {get; set;}
public double TotalMoneySpentTillThisBar {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
现在我想基于StartDate对ObservableCollection进行排序,以便BarData将在集合中按StartDate的顺序递增.然后我可以像这样计算每个BarData中TotalMoneySpentTillThisBar的值 -
var collection = new ObservableCollection<BarData>();
//add few BarData objects to collection
collection.Sort(bar => bar.StartData); // this is ideally the kind of function I was looking for which does not exist
double total = 0.0;
collection.ToList().ForEach(bar => {
bar.TotalMoneySpentTillThisBar = total + bar.MoneySpent;
total = bar.TotalMoneySpentTillThisBar;
}
);
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用ICollectionView对数据进行排序,过滤数据但不会改变实际的集合.我需要对实际集合进行排序,以便我可以为每个项目计算TotalMoneySpentTillThisBar.它的价值取决于集合中的项目顺序.
谢谢.
Gre*_*gfr 36
我首先要问你的问题是:你ObservableCollection的排序是非常重要的,还是你真正想要的是将GUI中的显示分类?
我假设目标是有一个"实时"更新的排序显示.然后我看到2个解决方案
得到ICollectionView你的ObservableCollection和排序,如
http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/
绑定你ObservableCollection的a CollectionViewsource,在它上面添加一个排序,然后使用它CollectionViewSource作为ItemSourcea ListView.
即:
添加此命名空间
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Run Code Online (Sandbox Code Playgroud)
然后
<CollectionViewSource x:Key='src' Source="{Binding MyObservableCollection, ElementName=MainWindowName}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="MyField" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Run Code Online (Sandbox Code Playgroud)
和这样绑定
<ListView ItemsSource="{Binding Source={StaticResource src}}" >
Run Code Online (Sandbox Code Playgroud)
Rac*_*hel 16
我刚刚创建一个扩展类ObservableCollection,因为随着时间的推移,我也希望其他的功能,我已经习惯了从使用List(Contains,IndexOf,AddRange,RemoveRange,等)
我经常使用类似的东西
MyCollection.Sort(p => p.Name);
这是我的排序实现
/// <summary>
/// Expanded ObservableCollection to include some List<T> Methods
/// </summary>
[Serializable]
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
/// <summary>
/// Constructors
/// </summary>
public ObservableCollectionEx() : base() { }
public ObservableCollectionEx(List<T> l) : base(l) { }
public ObservableCollectionEx(IEnumerable<T> l) : base(l) { }
#region Sorting
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void Sort<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderBy(keySelector));
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void SortDescending<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderByDescending(keySelector));
}
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderBy(keySelector, comparer));
}
/// <summary>
/// Moves the items of the collection so that their orders are the same as those of the items provided.
/// </summary>
/// <param name="sortedItems">An <see cref="IEnumerable{T}"/> to provide item orders.</param>
private void InternalSort(IEnumerable<T> sortedItems)
{
var sortedItemsList = sortedItems.ToList();
foreach (var item in sortedItemsList)
{
Move(IndexOf(item), sortedItemsList.IndexOf(item));
}
}
#endregion // Sorting
}
Run Code Online (Sandbox Code Playgroud)
mdm*_*m20 12
排序ObservableCollection的问题在于,每次更改集合时,都会触发一个事件.因此,对于从一个位置移除项目并将它们添加到另一个位置的排序,最终会发生大量事件.
我认为你最好的选择就是以正确的顺序将内容插入到ObservableCollection中.从集合中删除项目不会影响排序.我掀起了一个快速扩展方法来说明
public static void InsertSorted<T>(this ObservableCollection<T> collection, T item, Comparison<T> 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);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,如果您要使用字符串(例如),代码将如下所示
ObservableCollection<string> strs = new ObservableCollection<string>();
Comparison<string> comparison = new Comparison<string>((s1, s2) => { return String.Compare(s1, s2); });
strs.InsertSorted("Mark", comparison);
strs.InsertSorted("Tim", comparison);
strs.InsertSorted("Joe", comparison);
strs.InsertSorted("Al", comparison);
Run Code Online (Sandbox Code Playgroud)
编辑
如果扩展ObservableCollection并提供自己的插入/添加方法,则可以保持调用相同.像这样的东西:
public class BarDataCollection : ObservableCollection<BarData>
{
private Comparison<BarData> _comparison = new Comparison<BarData>((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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
插入索引被忽略.
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);
Run Code Online (Sandbox Code Playgroud)