Edit3:
I'm aware that the question is similar to others. The main difference, which isn't covered in those other questions is the fact that I need to achieve this with two seperate classes. I.e., starting the BGW in MainWindow
and running the DoWork
-method with the time consuming function in ConDB
.
I have two classes MainWindow
and ConDB
. With a buttonclick I call a method in ConDB, which does some time consuming stuff. Now I need my progressbar to update with every iteration of my loop.
For this, I have the following code with a backgroundworker:
private void btnConvert_Click(object sender, RoutedEventArgs e)
{
ConDB con = new ConDB();
date = tbDatum.Text;
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(con.worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerAsync();
}
RunWorkerAsync()
will call my DoWork
-Method in ConDB, hence con.worker_DoWork
In ConDB I call mw.worker.ReportProgress(progress)
to update the progressbar which, as you can imagine, throws an InvalidOperationException:
The calling thread cannot access this object because a different thread owns it.
Now I read a lot about using Dispatcher.CurrentDispatcher.BeginInvoke
since you can't access the UI thread from a backgroundworker thread. So far so good.
My problem now is, that I have no idea how to solve this issue with Dispatcher
, since I dont know where and how to write this code.
Also, I'm not sure if I'm doing things correctly with the backgroundworker. Do I need to define and instantiate it in my ConDB-class or can I keep it like this?
Any ideas, suggestions and help to educate me are much appreciated!
Edit:
public void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbProgressBar.Value = e.ProgressPercentage;
}
throws the exception.
Edit2:
So to provide a hopefully reproducable example, here's the sample code.
I call this method from MainWindow:
private void btnConvert_Click(object sender, RoutedEventArgs e)
{
ConDB con = new ConDB();
con.test();
}
Which would be this (in other class ConDB):
public void test()
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerAsync();
}
Which then calls the DoWork-method where I update my progressbar:
public void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 1000; i++)
{
percent++;
progress = percent * 100 / rows.Count();
worker.ReportProgress(progress);
}
}
ReportProgress then invokes this:
public void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
mw.pbProgressBar.Value = e.ProgressPercentage;
}
My aim at first was to start the backgroundworker in MainWindow
but to make my life easier and to test, I now call the method test
, which starts the BGW.