[英]Chain tasks using continuation task
我正在尝试链接任务,所以一旦完成下一个任务,但 UI 不会更新。 我做了一门反应课程,其中一课是根据应用程序中的状态更改更新 UI,这就是我想要复制的内容。 更改应用程序的状态(基本上我将运行运行返回 bool 进行验证的方法),然后相应地更新 UI,我也在使用绑定,但由于某种原因它没有按预期运行,我不不知道我是否错误地遵循了文档。 我可以更改或修复什么以使其工作,并且在单个async Task<T>
方法中使用多个任务实际上是否正确
public async Task<string> Connect_To_Ip()
{
await Task.Run(() =>
{
details.State = "Connection To IP 127.0.01.258.....";
Task.Delay(5000).Wait();
}).ContinueWith(result => new Task(async () =>
{
await Task.Run(() =>
{
if (result.Status == TaskStatus.RanToCompletion)
{
details.State = "Validating Card Number......";
}
});
}), TaskContinuationOptions.OnlyOnRanToCompletion);
return details.State;
}
我如何调用原始任务
Task connect = Connect_To_Ip();
await connect;
当您使用await
时,您不需要Task.ContinueWith
。 等待操作之后的一切都是延续。 由于要在后台线程上进行验证,因此必须将更改发布回 UI 线程以更新 UI 元素,否则将产生跨线程异常。
这是因为无法从后台线程更新 UI 元素,除非通过INotifyPropertyChanged
和数据绑定进行更新。
一种方法是使用Dispatcher
在 UI 线程上调用 UI 操作或使用Progress<T>
类,该类将始终在 UI 线程上执行注册的回调。
您的固定和简化代码可能如下例所示:
public async Task ValidateAsync()
{
// Register the callback that updates the UI with the 'progressReporter'
var progressReporter = new Progress<string>(message => details.State = message);
// Execute the operation on a background thread
await Task.Run(() => ConnectToIp(progressReporter));
// Continuation starts here, after await
}
public async Task ConnectToIp(IProgress<string> progressReporter)
{
progressReporter.Report("Connection To IP 127.0.01.258.....");
await Task.Delay(5000);
// Continuation starts here, after await
progressReporter.Report("Validating Card Number......");
}
建议尽可能使用异步 API,而不是使用后台线程。 例如,要在不阻塞 UI 的情况下连接到服务器,您可以使用
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
我在 Windows 窗体中执行此操作(我打开了一个测试 Windows 窗体项目),但在 WPF 中应该大致相同。 我在表单上放置了一个按钮、一个标签和一个文本框。 然后我写了这段代码:
private async void button1_Click(object sender, EventArgs e)
{
var result = await ValidateTextBox();
if (result != null)
{
label1.Text = result;
return;
}
var intResult = await ReadTextBox();
label1.Text = intResult.ToString();
await IncrementTextBox();
intResult = await ReadTextBox();
label1.Text = intResult.ToString();
}
private async Task<string> ValidateTextBox()
{
await Task.Delay(2000);
if (!int.TryParse(textBox1.Text, out _)) {
return "Not Valid";
}
//otherwise
return null;
}
private async Task<int> ReadTextBox()
{
await Task.Delay(3000);
if (!int.TryParse(textBox1.Text, out var result))
{
throw new Exception("Don't do that");
}
return result;
}
private async Task IncrementTextBox()
{
await Task.Delay(3000);
if (!int.TryParse(textBox1.Text, out var result))
{
throw new Exception("Don't do that");
}
textBox1.Text = (result + 1).ToString();
}
如果您在文本框中键入不是int
的内容并按下按钮,几秒钟后,标签中将显示Not Valid
。
如果那里有一个数字,那么会有一个暂停,这个数字会显示在标签中。 然后再次暂停,文本框编号将增加 1。最后,再次暂停后,标签将显示增加的值。
请注意,这一切都在单个线程上运行。 但是,尽管存在所有延迟,UI 始终保持响应。
在每个函数的开头和按钮单击处理程序中每个等待之后的行上放置断点。 逐步完成(而不是进入)整个过程,您将看到等待如何创建延续
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.