Reputation: 539
So this is my first foray into using delegates, events, Backgroundworkers, WPF...pretty much everything is new. I have an external class that runs a long running method that I would like to report progress on:
public class ShortFileCreator
{
public void CreateShortUrlFile(string outputfilepath)
{
foreach(string line in lines)
{
//work work work processing file
if (ReportProgress != null)
{
//report progress that a file has been processed
ReportProgress(this, new ProgressArgs {TotalProcessed = numberofurlsprocessed
, TotalRecords = _bitlyFile.NumberOfRecords});
}
}
}
public delegate void ReportProgressEventHandler (object sender, ProgressArgs args);
public event ReportProgressEventHandler ReportProgress;
public class ProgressArgs : EventArgs
{
public int TotalProcessed { get; set; }
public int TotalRecords { get; set; }
}
}
In my WPF Form, I want to kickoff the CreateShortUrlFile method and update the form's progress bar.
private void btnRun_Click(object sender, RoutedEventArgs e)
{
var shortFileCreator = new ShortFileCreator();
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
shortFileCreator.ReportProgress += ShortFileCreator_ReportProgress;
_worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
_bitlyFileWorker.CreateShortUrlFile(saveFileDialog.FileName);
};
_worker.RunWorkerAsync();
}
protected void ShortFileCreator_ReportProgress(object sender, ShortFileCreator.ProgressArgs e)
{
//update progress bar label
txtProgress.Content = String.Format("{0} of {1} Records Processed", e.TotalProcessed, e.TotalRecords);
//update progress bar value
progress.Value = (double) e.TotalProcessed/e.TotalRecords;
}
However when I run this, it processes one line and then I get the exception: The calling thread cannot access this object because another thread owns it. What other thread owns this? Shouldn't the ReportProgress event return ProgressArgs to any subscribers?
Upvotes: 0
Views: 1307
Reputation: 43596
This is because UI controls like the ProgressBar
and TextBox
can not be touched by another thread, in this case you are trying to update them from the BackgroundWorker
thread.
A way around this is to Invoke
the call back to the UI thread, you can do this using the Dispatcher
protected void ShortFileCreator_ReportProgress(object sender, ShortFileCreator.ProgressArgs e)
{
Dispatcher.Invoke((Action)delegate
{
//update progress bar label
txtProgress.Content = String.Format("{0} of {1} Records Processed", e.TotalProcessed, e.TotalRecords);
//update progress bar value
progress.Value = (double) e.TotalProcessed/e.TotalRecords;
});
}
Upvotes: 1