Vla*_*lad 1 c# asynchronous task winforms async-await
如果我在这样的任务中更新我的UI控件,它是否正确代码?
或者它是错的,我需要像Control.Invoke一样使用smth?
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text = await Task<string>.Factory.StartNew(() =>
{
Foo();
return "Completed";
});
}
private void Foo()
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
Thread.Sleep(1000);
}
}
Run Code Online (Sandbox Code Playgroud)
BCL使用在Progress类中实现的IProgress接口来解决此特定方案,以提供丰富的异步进度报告.这在.NET 4.5或带有BCL Portability Nuget包的.NET 4中可用.许多BCL类接受用于进度报告的IProgress参数.
Servy的答案解决了在异步操作之后如何更新UI的直接问题,但这迫使您在长时间运行的操作中混合UI代码.IProgress允许您使用报表数据进行OnReport调用,而无需担心将调用编组到正确的线程,同步上下文,UI特定的调用等.
您的代码可以像这样简单:
private async void button1_Click(object sender, EventArgs e)
{
var progress=new Progress<string>(msg=>textBox1.Text = msg);
await Task<string>.Factory.StartNew(() => Foo(progress));
}
private void Foo(IProgress<string> progress)
{
for (int i = 0; i < 100; i++)
{
progress.OnReport(i.ToString());
Thread.Sleep(1000);
}
progress.OnReport("Finished");
}
Run Code Online (Sandbox Code Playgroud)
或者您可以使用更复杂的进度类型,例如
class MyProgressData
{
public string Message{get;set;}
public int Iteration {get;set;}
public MyProgressData(string message,int iteration) ...
}
private async void button1_Click(object sender, EventArgs e)
{
var progress=new Progress<MyProgressData>(msg=>{
textBox1.Text = msg.Message;
textBox2.Text=msg.Iteration.ToString();
});
await Task<string>.Factory.StartNew(() => Foo(progress));
}
private void Foo(IProgress<MyProgressData> progress)
{
for (int i = 0; i < 100; i++)
{
progress.OnReport(new MyProgressData("Hi",i));
Thread.Sleep(1000);
}
progress.OnReport("Finished");
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,您可以完全将处理与报告分离.您可以将处理代码放在完全不同的类中,甚至可以从UI中进行投影.