Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 如何对ObservableCollection进行排序_Wpf_Sorting_Observablecollection_Icollectionview - Fatal编程技术网

Wpf 如何对ObservableCollection进行排序

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和一个WPF UserControl数据绑定到它。控件是一个图形,显示ObservableCollection中BarData类型的每个项的垂直条

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