WPF element bound to observable collections updated on worker thread

I have been dealing with multithreading issues for years. Over the past few days, I've been trying to ensure that all my calls are thread-safe. I just ran into a problem that threw me. Here's the script:

I am trying to plot a waveform using the Infragistics XamDataChart control that is streaming ~ 500 dots / sec / waveform. After starting the application, I create objects that have an ObservableCollection WaveData property and these properties are bound directly to the xaml in the itemcontrol. When data enters it, it is stored in a queue, and the spawned worker thread is used to remove data from the queue and update the collection at the appropriate position.

Workday flow:

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

      

The code to update the collection, which is executed in a loop (some lines of code are 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 am not actually adding / removing items to / from the collection, but just updating the item at a specific position. This is because I wanted it to look like a patient monitor in a hospital.

The problem I am running into is that I realized that I am updating this collection on a non-interface stream and this collection is bound to the Infragistics LineSeries directly ... and this works... However, another graph using Infragistics StepLineSeries throws an exception when I update this collection on a non-UI thread that is expected. How is it possible that I can update the associated collection on a non-UI thread? I am concerned about this because 1) sometimes I get an error that the collection cannot be updated on a non-UI thread and 2) when I switched the waveform update to the UI thread via the dispatcher, the performance was so bad that the graphical the interface was unusable. I need to understand why this works, so I know how to proceed. I don't want to deploy an application that can fail at any time due to improper flow control on my part. I'm looking for possible reasonswhy / how one would update the bound ObservableCollection to a non-UI thread. Any help / suggestions would be appreciated.

+3


source to share


3 answers


You might need to look into using the Dispatcher (unless some of your code has been omitted).

You can use the Dispatcher method when performing an operation that requires code to run on the UI thread.

Perhaps you could get this data on the background worker thread and propagate the changes back to the UI thread when your collection is updated.



eg.

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

      

+3


source


Try using the invoke dispatcher to make sure the collection is available through the UI thread, thereby preventing other events from triggering the non-interface thread.



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

      

+1


source


The answer I was looking for is that you can update the properties of the data binding object and WPF will take care of the dispatch 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 element value at a specific index. However, in another scenario, I always added and removed points.

0


source







All Articles