当我必须做很多与GUI合作的简短任务时,我是否应该为每个任务或其他解决方案使用另一个BackgroundWorker
?
修改
我的意思是每5秒更新一次datagridview(200行x 50列)中的每个单元格。每个单元都存储图像。
答案 0 :(得分:2)
当我处理许多小任务时,我倾向于发现ThreadPool
是处理它们的好方法。您可以在后台线程上调度委托,如下所示:
ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadProc));
您还可以将对象传递给线程作为其状态,考虑将对象作为参数的委托。你可以这样称呼:
ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadProc), state);
其中state是某个对象,你的线程知道如何处理。
修改:ThreadPool
方法适用于您的方案。只需确保必须在GUI线程上调用任何更改GUI的代码,否则您将获得一些跨线程异常。
答案 1 :(得分:2)
BackgroundWorker
更适合长时间运行的任务,你想要ThreadPool之类的东西。这是一个非常粗略的例子:
QueueUserWorkItem
允许您指定一个worker方法并传入一个对象以供该方法使用。
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), object);
然后你会得到所有魔法发生的DoWork
方法:
public void DoWork(object sender)
{
object s = (object)sender;
this.Invoke(new ThreadDone(ReportProgress), result);
}
请注意对this.Invoke(new TaskDone(ReportProgress));
的调用这会安全地调用主线程上运行的代码,以使用DoWork
中处理过的数据更新您的UI。这是通过私人代表完成的:
private delegate void ThreadDone(object yourObject);
哪个会打电话:
private void ReportProgress(object yourObject)
{
//update UI
}
您也可以通过跟踪Interlocked
计数器对象来检查任务何时完成,例如。
foreach (string s in strings)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), s);
Interlocked.Increment(ref workItems);
}
然后在单个线程完成时递减workItems
并在workItems == 0
Interlocked.Decrement(ref workItems);
if (workItems == 0)
{
this.Invoke(new TaskDone(WorkComplete));
}
希望这有帮助。