我发现对我目前的情况来说,这似乎是一个非常简单的解决方案。
我目前的情况是我想在一个新的线程上做一些I / O操作,所以我不会陷入我的GUI线程。我有一个函数,作为我的Form的成员,已经执行了这些I / O操作,但在GUI Thread上运行它确实使应用程序很难使用。所以我的计划是在新的Thread中运行这个函数。所以,我以我的形式创建了一个Thread变量,并试图让它将该函数用作ThreadStart参数。但它似乎并不喜欢它。
我找到了一个优雅的解决方案,作为对另一个帖子here的回复。
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
从该响应的外观来看,我可以在新的Thread中运行此函数,然后在Thread完成计算时使用匿名函数来更新我的Form。不过,我只是不足以填补那个回复中的空白。
我似乎读到的关于Threads的所有内容都说我的ThreadStart函数需要是新类中的静态方法。该响应似乎表明我可以在我的Form类中执行它,因此this
引用仍然引用我的Form实例。否则,如果我的ThreadStart参数是一个不同的类,我必须传入对Form实例的引用,这似乎更多的代码,对吧?
有人会介意帮助我填写回复的背景吗?提前谢谢!
答案 0 :(得分:1)
有很多方法可以做到这一点。一个非常简单,直截了当的版本就是使用BackgroundWorker。它专为这种情况而设计。它有一个在后台线程中运行的DoWork
方法,以及在UI线程中运行的工作完成后触发的Completed
事件(因此您不需要调用invoke或任何东西)用结果更新UI)。它甚至内置了报告进度支持(报告进度事件也在UI线程中运行),因此您可以轻松更新进度条或状态文本。
MSDN也有一些examples,你可以通过一些简单的搜索找到更多。
通过C#4.0提供的另一个选项是使用Tasks
。您可以启动一个将在后台线程中运行的新任务,然后您可以添加一个将在UI线程中的延续。
这是一个简单的例子:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => doStuffInBackground())
.ContinueWith(task => updateUI(), TaskScheduler.FromCurrentSynchronizationContext());
}
private void updateUI()
{
throw new NotImplementedException();
}
private void doStuffInBackground()
{
throw new NotImplementedException();
}
你当然可以在我所拥有的实际lambda中做任何你想做的事,或者你甚至可以删除lambdas并直接将方法放在那里,只要你确保签名是正确的。如果需要,您还可以继续链接这些延续,例如,允许您执行任务1,更新标签,然后执行任务2,更新标签等。主要缺点是它不擅长更新进度条经常在循环内部,BackgroundWorker
的方式。