I made a wrapper class around 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.
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.
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.
NOTE 2: I have override the toString() method, which I forgot to mention :
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...
You are not correctly create the event object 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:
Initializes a new instance of the NotifyCollectionChangedEventArgs class that describes an Add or Remove change.
NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction, Object, Int32)
UPDATE 0
Also it is better not to use an overload of method ToString
to compare items, and use the special IComparer<TKey>
for this.
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);
}
}