mdutra
mdutra

Reputation: 393

WPF element bound to observablecollection updated on worker thread

I have been dealing with multithreading issues for a while now. In the past few days I have been trying to ensure all my calls are thread safe. I have just run into an issue that has thrown me. Here is the scenario:

I am attempting to plot a waveform, using an Infragistics XamDataChart control, which is passed ~500 points/sec/waveform. Upon launch of the application I create objects that have an ObservableCollection property called WaveData and these properties are bound directly to the xaml in an itemscontrol. When the data comes in it is stored in a Queue and a spawned worker thread is used to dequeue the data and update the collection at the appropriate position.

Spawn worker thread:

QueueProcessThread = Task.Factory.StartNew(() => UpdateWaveFormCollections(WaveForms), tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

Code to update the collection which runs in a loop (some lines of code omitted for brevity):

waveForm.LastDisplayedTimeStamp = DateTime.Now; // move the last displayed time up

int collectionSize = waveForm.WaveData.Count; 
while (waveForm.WaveDataBuffer.Count > 0 && waveForm.WaveDataBuffer.Peek().TimeStamp < waveForm.LastDisplayedTimeStamp)
{
   if (waveForm.CurrentPosition >= collectionSize)
   {
      waveForm.CurrentPosition = 0;
   }
   waveForm.WaveData[waveForm.CurrentPosition] = waveForm.WaveDataBuffer.Dequeue();
   waveForm.CurrentPosition++;
}

As you can see, I do not actually add/remove items to/from the collection but instead just update the item at a specific position. This is because I wanted it to look like a patient monitor at a hospital.

The problem I am running into is that I realized that I am updating this collection on a non UI thread and that collection is bound to the Infragistics LineSeries directly...and this is working. However, another graph using an Infragistics StepLineSeries throws an exception when I update that collection on a non UI thread which is expected. How is it possible that I am able to update a bound collection on a non UI thread? I am concerned by this because 1) occasionally I do get an error that a collection cannot be updated on a non UI thread and 2) when I switched the waveform update to be on the UI thread via a dispatcher the performance was so bad the GUI was unusable. I need to understand why this works so I know how to proceed. I do not want to deploy an application that might fail at any time due to thread mismanagement on my part. I am looking for possible reasons why/how it might be possible to update a bound ObservableCollection on a non UI thread. Any help/suggestions would be appreciated.

Upvotes: 3

Views: 1699

Answers (3)

kevchadders
kevchadders

Reputation: 8335

Maybe you need to look into using the Dispatcher (unless thats part of your code omitted).

You can use the Dispatcher method when you do an operation that will require code to be executed on the UI thread.

Maybe you could retrieve that data in the background worker thread and when you update your collection propagate changes back to the UI thread

e.g.

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
  new Action(() => methodHere = 50));

Upvotes: 3

mdutra
mdutra

Reputation: 393

The answer I was looking for is that you can update properties of a databound object and WPF will take care of the dispatching for you, however, you cannot update collections (add/remove/clear) from a non UI thread. In my waveform I was not adding points but updating the value of the item at a specific index. However, in the other scenario I was always adding and removing points.

Upvotes: 0

VidasV
VidasV

Reputation: 4895

Try using dispatcher invoke to make sure the collection will be accessed through UI thread, thus not allowing any other events to fire on a non UI thread.

Application.Current.Dispatcher.BeginInvoke(new Action(()=>
{
// code here to access collection
}));

Upvotes: 1

Related Questions