以下是一个简单的例子:
public event EventHandler CookinDone = delegate{};
public void CoockinRequest(){
var indicator = new ActivityIndicator();
ActivityIndicator.Show("Oooo coockin' something cool");
var bw = new BackgroundWorker();
bw.DoWork += (sender, e) => CockinService.Cook();
bw.RunWorkerCompleted += (sender, e) => {
indicator.Hide();
CookinDone.Invoke(this,null);
};
bw.RunWorkerAsync();
}
现在,每次我使用该方法时,我都必须拦截CookinDone事件并继续前进。
var cook = new Cook();
cook.CookinDone += (sender, e) => MessageBox.Show("Yay, smells good");
cook.CoockinRequest();
但是如何通过将方法的返回类型设置为布尔值并在Cookin完成时返回结果来简化它?
if (CoockinRequest()) MessageBox.Show('Yay, smells even better');
如果我放在while (bw.IsBusy)
之类的东西,它会拧我的ActivityIndicator,冻结主线程,我觉得这将是最糟糕的事情。还有一些Monitor.Wait
的东西和其他一些东西,比如TaskFactory
,但所有这些东西似乎都太复杂了,无法在简单的场景中使用。
在不同的环境中它可能也有所不同,比如某些方法对WPF应用程序有用,有些对于其他东西有什么好处,但是应该有一般模式不对吗?
你是怎么做那些人的?
答案 0 :(得分:7)
在.NET 4中没有直接的方法。这实际上非常符合下一版C#中新的async / await功能。
可以在.NET 4中使用任务并行库来实现此目的。您可以通过更改代码返回Task<bool>
来执行此操作,以便调用者可以等待它(如果需要),或者在完成此任务时运行的任务上订阅 continuation
为此,你要重写上面的代码:
public Task<bool> CoockinRequestAsync()
{
var indicator = new ActivityIndicator();
ActivityIndicator.Show("Oooo coockin' something cool");
// This assumes Cook() returns bool...
var task = Task.Factory.StartNew(CockinService.Cook);
// Handle your removal of the indicator here....
task.ContinueWith( (t) =>
{
indicator.Hide();
}, TaskScheduler.FromCurrentSynchronizationContext());
// Return the task so the caller can schedule their own completions
return task;
}
然后,当你去使用它时,你会写出类似的东西:
private void SomeMethod()
{
var request = this.CoockinRequestAsync();
request.ContinueWith( t =>
{
// This will run when the request completes...
bool result = t.Result;
// Use result as needed here, ie: update your UI
}, TaskScheduler.FromCurrentSynchronizationContext());
}