简体   繁体   English

SortedList似乎没有排序

[英]SortedList doesn't seem to be sorting

I made a wrapper class around SortedList. 我围绕SortedList创建了一个包装器类。 I add objects to this class expecting them to be automatically sorted alphabetically, but when I bind to a ListBox in WPF, I see then in unsorted order. 我向此类添加了对象,希望它们可以按字母顺序自动排序,但是当我绑定到WPF中的ListBox时,我看到的是未排序的顺序。

public class SortedObservableCollection<T> : ICollection<T>, INotifyPropertyChanged, INotifyCollectionChanged where T : INotifyPropertyChanged//, IComparable<T>
{
    private readonly SortedList<string,T> _innerSortedList;

    public SortedObservableCollection()
    {
        _innerSortedList = new SortedList<string, T>();
    }

    public void Add(T item)
    {
        _innerSortedList.Add(item.ToString(), item);
        this.OnPropertyChanged("Count");
        this.OnPropertyChanged("Item[]");
        this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
        item.PropertyChanged += ItemPropertyChanged;
    }

    void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public void Clear()
    {
        _innerSortedList.Clear();
    }

    public bool Contains(T item)
    {
        return _innerSortedList.ContainsKey(item.ToString());
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public int Count
    {
        get { return _innerSortedList.Count; }
    }

    public bool IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    public bool Remove(T item)
    {
        bool success = _innerSortedList.Remove(item.ToString());
        if (success)
        {
            item.PropertyChanged -= ItemPropertyChanged;
            this.OnPropertyChanged("Count");
            this.OnPropertyChanged("Item[]");
            this.OnCollectionChanged(NotifyCollectionChangedAction.Remove, item);
        }
        return success;
    }

    public IEnumerator<T> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _innerSortedList.GetEnumerator();
    }

    protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, object item)
    {
        if (this.CollectionChanged != null)
        {
            this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public event NotifyCollectionChangedEventHandler CollectionChanged;
}

To bind I simply do : 绑定我只是做:

SortedObservableCollection<IRCUser> Users { get; private set; }
.. fill users...
lstUsers.ItemsSource = users;

Sample input : 样本输入:

5Muhammad0
2Muhammad1
5Muhammad2

The output also shows similar, with the ones beginning with 2, 4 etc riddled between the 5's. 输出也显示类似,其中以2、4等开头的数字介于5之间。

Note: My IRCUser class did implement IComparable, but since I only want an alphabetical sort now I commented the implentation out hoping the default sorting would kick in. 注意:我的IRCUser类确实实现了IComparable,但是由于我现在只希望按字母顺序排序,因此我评论了这种情况,希望可以进行默认排序。

NOTE 2: I have override the toString() method, which I forgot to mention : 注意2:我已经重写了toString()方法,我忘记提及了:

public override string ToString()
{
    return (int)Type + Nick;
}

UPDATE : 更新:

It seems internally the sortedList maintains the right order, but it is not passed to the ListBox in the right order... 在内部似乎sortedList保持正确的顺序,但是它没有以正确的顺序传递给ListBox

You are not correctly create the event object NotifyCollectionChangedEventArgs . 您没有正确创建事件对象NotifyCollectionChangedEventArgs This object has different overloads of constructor depending on the action. 根据操作,此对象具有不同的构造函数重载。 You must use the overload that uses the index of the new item when you create a new item: 创建新项目时,必须使用使用新项目索引的重载:

new NotifyCollectionChangedEventArgs(action, item, index)

Here's quote from MSDN: 这是MSDN的报价:

Initializes a new instance of the NotifyCollectionChangedEventArgs class that describes an Add or Remove change. 初始化一个NotifyCollectionChangedEventArgs类的新实例,该实例描述添加或删除更改。

NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction, Object, Int32)

UPDATE 0 更新0

Also it is better not to use an overload of method ToString to compare items, and use the special IComparer<TKey> for this. 另外最好不要使用方法ToString的重载来比较项目,并为此使用特殊的IComparer<TKey> In your case, the correct code looks like this: 在您的情况下,正确的代码如下所示:

public void Add(T item)
{
    var key = item.ToString();
    _innerSortedList.Add(key, item);
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _innerSortedList.IndexOfKey(key)));
    item.PropertyChanged += ItemPropertyChanged;
}

public bool Remove(T item)
{
    var indexOfKey = _innerSortedList.IndexOfKey(item.ToString());
    if (indexOfKey == -1)
        return false;
    _innerSortedList.RemoveAt(indexOfKey);
    item.PropertyChanged -= ItemPropertyChanged;
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item,
        indexOfKey));
    return true;
}

public IEnumerator<T> GetEnumerator()
{
    return _innerSortedList.Values.GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
    var handler = this.CollectionChanged;
    if (handler != null)
    {
        handler(this, args);
    }
}

You are sorting your data on item.ToString() which may not be a very useful value to sort on. 您正在对item.ToString()上的数据进行排序,这对排序不是一个非常有用的值。

Unless it is overridden, it will be the type name of the class and therefore the same for everything you add. 除非被覆盖,否则它将是该类的类型名称,因此对于您添加的所有内容都是相同的。


This obviously leads to the question, how should generic data be sorted. 显然,这引出了一个问题,即应如何对通用数据进行排序。 This is what IComparable<T> is for. 这就是IComparable<T>目的。


You'll note that there are several SortedList<T> constructors that allow you to pass an IComparable implementation to define your own order. 您会注意到,有几个SortedList<T> 构造函数使您可以传递IComparable实现来定义自己的顺序。

In any case, if you want to use the default IComparable implementation of string, you will need to use strings that differ in accordance with your desired order. 无论如何,如果要使用默认的IComparable字符串实现,则将需要使用根据所需顺序不同的字符串。 Not type names that do not differ at all. 请勿键入完全相同的名称。

The problem is with 问题出在

_innerSortedList.Add(item.ToString(), item);

Let suppose if item is of type Project.Test.CustomEntity then item.ToString() will give you " Project.Test.CustomEntity " which is getting sorted by Entity's fullname and not by the value. 假设如果item的类型为Project.Test.CustomEntityitem.ToString()将为您提供“ Project.Test.CustomEntity ”,该名称将按Entity的全名而不是按值进行排序。

you need to write a custom sorter based on property selector of your T. 您需要根据您的T的属性选择器编写一个自定义排序器。

Have a look at this article . 看一下这篇文章

I'm not sure but: 我不确定,但是:

1) If the UI has a data template, and the sample output you showed there is not the result of IRCUser.ToString() - than, maybe, the ToString() does not provide a "good" hash value for sorting. 1)如果UI具有数据模板,并且您显示的示例输出没有IRCUser.ToString()的结果-则ToString()可能没有提供用于排序的“良好”哈希值。

2) You may be better served by using a PagedCollectionView to wrap your collection, and set the ordering there. 2)使用PagedCollectionView包装您的集合并在那里设置顺序可能会更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM