之前我没有做太多多线程,现在发现需要做一些后台工作并保持UI响应。我有以下代码。
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);
}
但是,由于在后台线程上进行ImportProgressChanged()
调用,因此UI不会更新。在目标C中我知道你可以使用performSelectorOnMainThread并传递一个方法来使用主线程进行调用。从主线程调用ImportProgressChanged()
的等效方法是什么?
答案 0 :(得分:2)
(假设使用Windows窗体。)您可以使用Control.Invoke
或Control.BeginInvoke
- 但可以更清洁的方式使用BackgroundWorker
开始。
在WPF中,您使用Dispatcher
代替Control.Invoke
,顺便说一下。有关详细信息,请参阅此WPF threading model guide。
编辑:我个人可能不会先打扰InvokeRequired
- 我只需拨打Invoke
或BeginInvoke
。如果你已经“开启”正确的线程,它将不会造成任何重大伤害。
对于进度条,BackgroundWorker
绝对是前进的方向。
答案 1 :(得分:1)
而不是更新GUI,data_ImportProgressChanged应该在被调用时抛出异常更改进度条。
最短的更改是使用Control.InvokeRequired和.Invoke(),但Backgroundworker是专为此方案创建的。
如果你想在数据对象中解决它,你必须依赖于GUI,所以最好在处理程序中解决这个问题:
void data_ImportProgressChanged(int progress)
{
if (toolStripProgressBar.InvokeRequired)
{
Action<int> a = new Action(data_ImportProgressChanged);
toolStripProgressBar.Invoke(a, progress);
}
else
toolStripProgressBar.Value = progress;
}
答案 2 :(得分:0)
你已经有了答案,但无论如何我都会添加我的解决方案:
void data_ImportProgressChanged(int progress)
{
if (InvokeRequired)
{
BeginInvoke(new Action<int>(data_ImportProgressChanged),progress);
return;
}
toolStripProgressBar.Value = progress;
}