Introduction
I was working on a WPF project where I had the ViewModel
mirroring the Model
displaying a hierarchical view of the data (like a tree view, but using XamDataGrid
). I wanted to have an event in the Model that triggered when a record was added or removed to reduce coupling (probably when changes are made in the Model in the future). This was because I expected to be using the Model side with many different ViewModels, although at this point not sure since I am being given the requirements piece-meal. When I did this in a case where I had a BackgroundWorker
, I started having problems with being on the wrong thread. Of course I expected that, and I immediately implemented a Dispatcher on the receiving class using code like the following:
Dispatcher.CurrentDispatcher.Invoke(new Action<StagedBlotterOrderAggViewModel>(Add), adding);
This did not work so I attempted to use DispatcherPriority
. Nothing looked right to me, but I tried several options and none worked.
I could go back to a design of trying to ensure that the record updates were done in the BackgroundWorkerCompleted
handler, but that would complicate the code.
Of course I know that you can get the Dispatcher from the control, but that was not very elegant. Therefore I started to search the web, and found something interesting at “Have worker thread update ObservableCollection
that is bound to a ListCollectionView
” (http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx). I was not sure it would work, but I tried it, and it did. Of course I guess eventually I would have come up with inheriting from ObservableCollection<T>
since I knew that I could get the Dispatcher from the control and then would not have had to do anything special in the ViewModel
, but I am sure this is better than what I would have come up with. I did make a small number of improvements of adding the other constructors.
Here is my slightly improved version of this code that worked so well for me:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Threading;
namespace Custom.Collections
{
public class ObservableCollectionEx<t> : ObservableCollection<t>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableCollectionEx(IEnumerable<t> collection) : base(collection) { }
public ObservableCollectionEx(List<t> collection) : base(collection) { }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
using (BlockReentrancy())
{
var eventHandler = CollectionChanged;
if (eventHandler != null)
{
Delegate[] delegates = eventHandler.GetInvocationList();
foreach (NotifyCollectionChangedEventHandler handler in delegates)
{
var dispatcherObject = handler.Target as DispatcherObject;
if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind,
handler, this, e);
else
handler(this, e);
}
}
}
}
}
}</t></t></t></t>
Now my big question is: Why didn’t Microsoft provide this in the original ObservableCollection
?