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
?
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.