I haven't done much multithreading before and now find the need to do some background work and keep the UI responsive. I have the following code.
data.ImportProgressChanged += new
DataAccess.ImportDelegate(data_ImportProgressChanged);
Thread importThread = new Thread(
new ThreadStart(data.ImportPeopleFromFAD));
importThread.IsBackground = true;
importThread.Start();
void data_ImportProgressChanged(int progress)
{
toolStripProgressBar.Value = progress;
}
//In my data object I have
public void ImportPeopleFromFAD()
{
ImportProgressChanged(someInt);
}
But the UI doesn't get updated since the ImportProgressChanged()
call is made on the background thread. In objective C I know you can use performSelectorOnMainThread and pass it a method to call usi开发者_JAVA百科ng the main thread. What is the equivalent way of calling ImportProgressChanged()
from the main thread?
(Assuming Windows Forms.) You can use Control.Invoke
or Control.BeginInvoke
- but a cleaner way may be to use BackgroundWorker
to start with.
In WPF you'd use a Dispatcher
instead of Control.Invoke
, btw. See this WPF threading model guide for more details.
EDIT: Personally I probably wouldn't bother testing InvokeRequired
first - I'd just call Invoke
or BeginInvoke
. If you're already "on" the right thread it won't do any significant harm.
For progress bars, however, BackgroundWorker
is definitely the way forward.
Instead of updating the GUI, data_ImportProgressChanged should throw an exception when it gets called changes the progressbar.
The shortest change is to use Control.InvokeRequired and .Invoke(), but the Backgroundworker was especially created for this scenario .
If you want to solve it in the data object you will have to make that depend on the GUI so its better to solve this in the handler:
void data_ImportProgressChanged(int progress)
{
if (toolStripProgressBar.InvokeRequired)
{
Action<int> a = new Action(data_ImportProgressChanged);
toolStripProgressBar.Invoke(a, progress);
}
else
toolStripProgressBar.Value = progress;
}
You already have your answer but I'll add my solution anyway:
void data_ImportProgressChanged(int progress)
{
if (InvokeRequired)
{
BeginInvoke(new Action<int>(data_ImportProgressChanged),progress);
return;
}
toolStripProgressBar.Value = progress;
}
精彩评论