0

I'm trying to download some movie data in a BackgroundWorker thread, but when the background thread tries to modify ObservableCollection fields for the selected movie there is an error stating "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread".

First I tried removing any UI elements such as TextBoxes before running the BackgroundWorker, which strangely didn't seem to work even though there were no objects left to synchronize changes.

I can get around this by using the answer here to send the changes to the UI thread but it means I'd have to flood my background thread with many lines like uiContext.Send(x => _matchObsCollection.Add(match), null); which would make my code a little messier than I'd like.

Ideally I'd like to remove the SynchronizationContext so that the UI thread would not try to interfere with the background thread, but again this isn't making any difference. Is there something wrong with what I'm trying to do here:

// Prevent synchronization with the UI thread.
var uiContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);

// Prepare the background worker for data download tasks.
BackgroundThread = new BackgroundWorker();
BackgroundThread.WorkerReportsProgress = true;
BackgroundThread.ProgressChanged += BackgroundThread_ProgressChanged;
BackgroundThread.DoWork += (f, arg) =>
{
    DownloadMovieData(movie, uiContext);
};
CSDev
  • 3,177
  • 6
  • 19
  • 37
ChrisUK
  • 547
  • 8
  • 17
  • 1
    Well ... to start with you should be using Task objects rather thank BackgroundWorkers, and Tasks allow you to return completed sets of work. – Steve Todd Jul 23 '19 at 11:20
  • @SteveTodd OK, but can you use something like ReportProgress to update progress bars and such like using Task objects? The data download task is quite long so I'd need to keep that functionality. – ChrisUK Jul 23 '19 at 13:51
  • @ChrisUK What information did you find when searching for "C# Progress Bars Tasks" to indicate if it is in fact possible or how one might do it, and how did the results you found fail to answer your question? – Servy Jul 23 '19 at 13:54
  • @ChrisUK, you're using WPF. Any thread you want can change a value in a view model (and thus update your progress bar). Background workers were something that was created for WinForms. – Steve Todd Jul 23 '19 at 14:11
  • @SteveTodd OK thanks I didn't know that. – ChrisUK Jul 23 '19 at 14:16
  • @Servy What's with the hostility? It was a reasonable question to ask while I was trying to digest the information elsewhere on the page. – ChrisUK Jul 23 '19 at 14:16
  • @ChrisUK It's not hostility. I'm asking you what you found when researching the answer to the question that you have, to know why you weren't able to solve it. It is of course an entirely reasonable question to have, but one that is solved by simply searching for the answer and seeing the numerous quality results on the topic. Unless you for some reason had a problem using the information out there on the topic, in which case it's important to know what about the existing available information on the topic was causing problems for you. – Servy Jul 23 '19 at 14:18
  • @Servy Easy. Cool down a little bit, please. – BionicCode Jul 23 '19 at 14:20
  • @ChrisUK Check my answer. Use [`Progress`](https://learn.microsoft.com/en-us/dotnet/api/system.progress-1?view=netframework-4.8) to do it instead. Also check [this](https://blog.stephencleary.com/2012/02/reporting-progress-from-async-tasks.html) example if you like. – BionicCode Jul 23 '19 at 14:22
  • @BionicCode Your method seemed to be good, but Livio's suggestion just happened to be the one I tried first (and it got around the issue). Thanks for your help. – ChrisUK Jul 23 '19 at 14:55

1 Answers1

2

You could try to store the result of the DownloadMovieData function on a temporary variable and add a RunWorkerCompleted event to your background worker to set the actual ObservableCollection to the value of the temporary variable you created.

  • This is probably not the most elegant way of doing this, but it seemed the easiest way to get around my problem - so thanks. – ChrisUK Jul 23 '19 at 14:49