For my WPF project I need an observable collection that always keeps the correct order. My idea is to use a SortedSet<T> and implement my own AddAndNotify and RemoveAndNotify methods. In them, I would call NotifyPropertyChanged, like this:
public class ObservableSortedSet<T> : SortedSet<T>, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public void AddAndNotify(T element)
{
Add(element);
NotifyPropertyChanged(...);
}
public void RemoveAndNotify(T element)
{
Remove(element);
NotifyPropertyChanged(...);
}
}
But which property (or properties) would that be?
How can one implement a collection that tells the UI to update whenever the collection contents change?
Or is there an easier way by using the SortedSet directly in my ViewModel?
EDIT:
I don't want to use the predefined ObservableCollection together with a sorted view. I know this is possible by using either CollectionViewSource or converters, but these solutions don't appeal to me. I have hierarchichal data for which CollectionViewSource doesn't work, and I consider the converter version a horrible workaround for the limits of CollectionViewSource. I want to use a clean solution.
So this question is not a duplicate of how to sort ObservableCollection . I don't want to sort an ObservableCollection, I want to use a SortedSet that can tell changes to the UI.
You should implement INotifyCollectionChanged Interface instead.
public class ObservableSortedSet<T> : SortedSet<T>, INotifyPropertyChanged, INotifyCollectionChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event NotifyCollectionChangedEventHandler CollectionChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public void AddAndNotify(T element)
{
Add(element);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
public void RemoveAndNotify(T element)
{
Remove(element);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));
}
}
I managed to do it this way:
public class ObservableSortedSet<T> : SortedSet<T>, INotifyCollectionChanged where T : IComparable<T>
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public new void Add(T element)
{
base.Add(element);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public override void Clear()
{
base.Clear();
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new void Remove(T element)
{
base.Remove(element);
CollectionChanged?.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Why did I always give the Reset action as EventArg?
Reason for Remove: It seems to be unable to be utilized if the collection does not have indices (see Implementing INotifyCollectionChanged on a collection without indexes or Observable Stack and Queue - in both cases it boils down to not being able to specify the correct index, resulting in a runtime error. Look at all the comments below the answers saying "index xyz doesn't work for me!".)
Reason for Add: Internally, the Collection IS sorted, but the UI does not reflect this correctly. My guess is that by giving the EventArg new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, element); the GUI only gets notified that the new element should be added TO THE END.
According to https://msdn.microsoft.com/en-us/library/system.collections.specialized.notifycollectionchangedaction(v=vs.100).aspx, Reset stands for "The content of the collection changed dramatically." This is kind of true for SortedSet, since its internal structure can change a lot if just one element is added or removed. So maybe my solution isn't even a workaround (even if it feels like one)!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With