I am trying to implement the following requirements (C# 4.0);
- One "producer" (on the UI thread - driven by user action) which submits upload requests
- A
ListView
control which is databound to the collection of pending upload requests - One consumer which process the requests (FIFO), and keeps the UI up-to-date as items status' update, or the request is fulfilled.
So far, I haven't been able to work out how to do the above without using two collections, as follows;
public void AddUploadRequest(UploadRequest uploadRequest)
{
this.UploadRequests.Add(uploadRequest);
this.uploadRequestsBlocking.Add(uploadRequest);
}
... where UploadRequests
is an ObservableCollection<UploadRequest>
and uploadRequestsBlocking
is a BlockingCollection<UploadRequest>
The full code can be found here; http://pastebin.com/620EqaY5 (ignore the gross injection of Dispatcher - this is just prototype code so far)
I notify my UI of updates as follows;
this.dispatcher.Invoke(() => this.UploadRequests.Remove(uploadRequest));
Is there a better way to achieve this functionality? Or, more importantly, are there any serious drawbacks to this approach?
One possible extension I was considering was to have multiple consumers, by using Parallel.ForEach
over GetConsumingPartitioner
(based on this example). Would anything about the current approach make this unsuitable? It does work OK, but I'm not 100% confident that I haven't committed some major threading faux-pas somewhere along the way.
I would use
TPL
and no need for injecting theDispatcher
sinceTaskScheduler.FromCurrentSynchronizationContext()
will give me the currentDispatcher
of theMainUI
thread.The main (only) reason that you can't just databind to the BlockingCollection is that it does not implement INotifyCollectionChanged, so the UI would not get updated when a request is added / removed. That said, there are BlockingCollection wrappers around on the net that implement INotifyCollectionChanged. Or you could instead expose a CollectionView for the BlockingCollection and instead of dispatching a remove from an ObservableCollection, just dispatch a Refresh of the CollectionView.