Reputation: 50752
Why CollectionChanged event is virtual in ObservableCollection
? We have virtual OnCollectionChanged
method, which should be enough to override event call right?
I don't see any usage of this, and also virtual events are evil. ungainly usage of virtual events can bring a lot of logical issues, but however virtual events exists even in framework.
Is this just bad design or anyone use this in real-word?
Upvotes: 3
Views: 1970
Reputation: 11
I am afraid denis didn't answer the quesiton "Why CollectionChanged event is virtual?" but rather the question "Why OnCollectionChanged() method is virtual?". The first question is more properly answered by Jon. You may be interested in different handling of subscribers like I did some time ago. Let's have two different scenarios:
First scenario: I want to raise CollectionChanged event and be sure that any delegate that is invoked within this event (list of delegates), doesn't interrupt the invoking of the following delegates in case of an exception. In other words, an event is made of a list of delegates. If I have let's say 10 subscribers (delegates) and the 3rd delegate raises an exception, I may continue invoking the rest of delegates. Standard implementation interrupts invoking.
Second scenario: I may want to let some subscribers be prioritized (they receive the event earlier) even if they do the subscription later than others. In "add" event I can move some specific subscribers lower or higher in my custom list of delegates which is later used to raise the event..
Upvotes: 1
Reputation: 6316
We can debate about base classes and design, but here's a not direct/scholastic answer, but more of an example. I personally find it great that I could extend ObservableCollection and override OnCollectionChanged. ObservableCollection is very chatty, every time you add/remove items it bombards the UI thread with property changed messages and slows it down (in the datagrid, for example, every binding in it to be updated). So, as far as I know many people extend the ObservableCollection to suppress such notifications until they are done adding items. Just because WPF controls DataGrids/ListViews etc.. respond to CollectionChanged this works.
here's the usage, I refresh my data and instead of adding one item at a time, I populate a List then I reset the ObservableCollection with it just once which speeds up UI responsiveness enormously:
private void OnExecuteRefreshCompleted(IEnumerable<MyObject> result)
{
UiUtilities.OnUi(() => { _myObservableCollectionField.Reset(result, true);
});
here's my extended class:
public class ObservableCollectionExtended<T> : ObservableCollection<T>
{
private bool _suppressNotification;
//without virtual , I couldn't have done this override
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
}
public void Clear(bool suppressNotificationUntillComplete)
{
_suppressNotification = suppressNotificationUntillComplete;
Clear();
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void ClearItems(bool suppressNotificationUntillComplete)
{
_suppressNotification = suppressNotificationUntillComplete;
base.ClearItems();
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void AddRange(IEnumerable<T> list, bool suppressNotificationUntillComplete)
{
if (list == null)
throw new ArgumentNullException("list");
_suppressNotification = suppressNotificationUntillComplete;
foreach (T item in list)
Add(item);
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// clears old items, and new ones
/// </summary>
/// <param name="list"></param>
/// <param name="suppressNotificationUntillComplete"></param>
public void Reset(IEnumerable<T> list, bool suppressNotificationUntillComplete)
{
if (list == null)
throw new ArgumentNullException("list");
_suppressNotification = suppressNotificationUntillComplete;
Clear();
foreach (T item in list)
Add(item);
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Upvotes: 4