Wpf 如何对ObservableCollection进行排序
我有一个ObservableCollection和一个WPF UserControl数据绑定到它。控件是一个图形,显示ObservableCollection中BarData类型的每个项的垂直条Wpf 如何对ObservableCollection进行排序,wpf,sorting,observablecollection,icollectionview,Wpf,Sorting,Observablecollection,Icollectionview,我有一个ObservableCollection和一个WPF UserControl数据绑定到它。控件是一个图形,显示ObservableCollection中BarData类型的每个项的垂直条 ObservableCollection<BarData> class BarData { public DateTime StartDate {get; set;} public double MoneySpent {get; set;} public double T
ObservableCollection<BarData>
class BarData
{
public DateTime StartDate {get; set;}
public double MoneySpent {get; set;}
public double TotalMoneySpentTillThisBar {get; set;}
}
observedcollection
巴达类
{
公共日期时间起始日期{get;set;}
公共双倍货币支出{get;set;}
公共双TotalMoneySpentTillThisBar{get;set;}
}
现在我想根据StartDate对ObservableCollection进行分类,以便BarData在集合中的StartDate的顺序会越来越高。
然后我可以计算每个数据中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;
}
);
var collection=newobservetecollection();
//向集合中添加少量BarData对象
collection.Sort(bar=>bar.StartData);//理想情况下,这是我所寻找的那种不存在的函数
双倍合计=0.0;
collection.ToList().ForEach(bar=>{
bar.TotalMoneySpentTillThisBar=总计+bar.MoneySpended;
total=巴。TotalMoneySpentTillThisBar;
}
);
我知道我可以使用ICollectionView对数据进行排序和过滤,但这不会改变实际的收集。我需要对实际收款进行排序,以便计算每个项目的TotalMoneySpentTillThisBar。其值取决于集合中项目的顺序
谢谢。对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);
}
}
我刚刚创建了一个类,它扩展了
可观察集合
,因为随着时间的推移,我还需要从列表
中使用的其他功能(包含
,索引
,添加范围
,删除范围
,等等)
我通常把它和类似的东西一起使用
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
}
//
///扩展ObservableCollection以包括一些列表方法
///
[可序列化]
公共类ObservableCollectionEx:ObservableCollection
{
///
///建设者
///
public observeCollectionEx():base(){}
公共observeCollectionEx(列表l):基(l){}
公共ObservableCollectionEx(IEnumerable l):基(l){}
#区域排序
///
///根据键按升序对集合的项进行排序。
///
///由返回的密钥的类型。
///从项中提取键的函数。
公共无效排序(Func键选择器)
{
内部排序(Items.OrderBy(keySelector));
}
///
///根据键按降序对集合的项进行排序。
///
///由返回的密钥的类型。
///从项中提取键的函数。
public void排序结果(Func keySelector)
{
内部排序(Items.OrderByDescending(keySelector));
}
///
///根据键按升序对集合的项进行排序。
///
///由返回的密钥的类型。
///从项中提取键的函数。
///一个比较键的方法。
公共无效排序(Func键选择器、IComparer比较器)
{
内部排序(Items.OrderBy(keySelector,comparer));
}
///
///移动集合中的项目,使其顺序与提供的项目相同。
///
///用于提供项目订单的。
私有void InternalSort(IEnumerable sortedItems)
{
var sortedItemsList=sortedItems.ToList();
foreach(sortedItemsList中的var项)
{
移动(IndexOf(item),sortedItemsList.IndexOf(item));
}
}
#endregion//排序
}
我要问你的第一个问题是:
排序您的可观察集合
是否真的很重要,或者您真正想要的是对GUI中的显示进行排序
我假设目标是要有一个排序显示,将被“实时”更新。然后我看到两种解决方案
获取您的observedcollection
的ICollectionView
,并对其进行排序,如下所述
将您的ObservableCollection
绑定到CollectionViewsource
,在其上添加排序,然后将该CollectionViewsource
用作列表视图的ItemSource
i、 e:
添加此命名空间
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
然后
像这样捆绑
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);
<ListView ItemsSource="{Binding Source={StaticResource src}}" >
如何在不同的集合上使用LINQ对数据进行排序:
var collection = new List<BarData>();
//add few BarData objects to collection
// sort the data using LINQ
var sorted = from item in collection orderby item.StartData select item;
// create observable collection
var oc = new ObservableCollection<BarData>(sorted);
var集合=新列表();
//向集合中添加少量BarData对象
//使用LINQ对数据进行排序
var sorted=从集合orderby item中的项。开始数据选择项;
//创建可观察的集合
var oc=新的可观测集合(已排序);
这对我很有效。同样使用LINQ/Extensionmethod,可以避免触发NotifyPropertyChanged事件,方法是不将源列设置为排序列,而是清除原始列并添加排序列的项。(这将继续触发Collectionchanged事件(如果已实现)
公共子SortByProp(Of T)(ByRef c作为ICollection(Of T),PropertyName作为String)
尺寸l=c.ToList
Dim sorted=l.OrderBy(函数(x)x.GetType.GetProperty(PropertyName.GetValue(x))
c、 清除()
对于每一个我在排序
c、 加(i)
下一个
端接头
我知道这是一篇老文章,但我对大多数解决方案都不满意,因为它破坏了绑定。因此,如果有人遇到,这是什么
<CollectionViewSource x:Key='src' Source="{Binding MyObservableCollection, ElementName=MainWindowName}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="MyField" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<ListView ItemsSource="{Binding Source={StaticResource src}}" >
var collection = new List<BarData>();
//add few BarData objects to collection
// sort the data using LINQ
var sorted = from item in collection orderby item.StartData select item;
// create observable collection
var oc = new ObservableCollection<BarData>(sorted);
<Extension>
Public Sub SortByProp(Of T)(ByRef c As ICollection(Of T), PropertyName As String)
Dim l = c.ToList
Dim sorted = l.OrderBy(Function(x) x.GetType.GetProperty(PropertyName).GetValue(x))
c.Clear()
For Each i In sorted
c.Add(i)
Next
End Sub
public static void AddRangeSorted<T, TSort>(this ObservableCollection<T> collection, IEnumerable<T> toAdd, Func<T, TSort> sortSelector, OrderByDirection direction)
{
var sortArr = Enumerable.Concat(collection, toAdd).OrderBy(sortSelector, direction).ToList();
foreach (T obj in toAdd.OrderBy(o => sortArr.IndexOf(o)).ToList())
{
collection.Insert(sortArr.IndexOf(obj), obj);
}
}
public static void AddRangeSorted<T, TSort, TSort2>(this ObservableCollection<T> collection, IEnumerable<T> toAdd, Func<T, TSort> sortSelector, OrderByDirection direction, Func<T, TSort2> sortSelector2, OrderByDirection direction2)
{
var sortArr = Enumerable.Concat(collection, toAdd).OrderBy(sortSelector, direction).ThenBy(sortSelector2, direction2).ToList();
foreach (T obj in toAdd.OrderBy(o=> sortArr.IndexOf(o)).ToList())
{
collection.Insert(sortArr.IndexOf(obj), obj);
}
}
OrderLines.AddRangeSorted(toAdd,ol=>ol.ID, OrderByDirection.Ascending);