C# UI线程上的异步WPF多个状态更新
我希望从长时间运行的方法更新状态。通常我会使用dispatcher发回UI线程,但我对使用async Wait很好奇 为了简单起见: 创建一个窗口,添加一个按钮C# UI线程上的异步WPF多个状态更新,c#,wpf,asynchronous,async-await,C#,Wpf,Asynchronous,Async Await,我希望从长时间运行的方法更新状态。通常我会使用dispatcher发回UI线程,但我对使用async Wait很好奇 为了简单起见: 创建一个窗口,添加一个按钮 <Button Name="ButtonWithCodeBehind" Height="25" Click="ButtonWithCodeBehindOnClick"/> 这显然会中断,因为按钮WithCodeBehind.Content将在错误的线程上访问 有没有一种方法可以在不执行以下操作的情况下实现此功能: Depl
<Button Name="ButtonWithCodeBehind" Height="25" Click="ButtonWithCodeBehindOnClick"/>
这显然会中断,因为按钮WithCodeBehind.Content将在错误的线程上访问
有没有一种方法可以在不执行以下操作的情况下实现此功能:
Deployment.Current.Dispatcher.BeginInvoke(()=>ButtonWithCodeBehind.Content = "Second");
这里的关键是,长期运行的任务将随着进程生成更新,我可以将代码重构为如下内容:
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "First", scheduler)
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "Second", scheduler)
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "Third", scheduler);
});
}
但这是令人沮丧的。此外,如果您取出async和Wait关键字并用Task.WaitAll替换它们,它仍将按预期执行
注意:如果您想知道为什么我使用Thread.Sleep而不是Task.Delay,我实际上也在Silverlight中测试它,异步等待支持不包括.Delay(或者至少不包括我预期的延迟)。唯一需要等待的部分是长时间运行的部分—IO调用,或者在本例中,CPU限制的睡眠
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
ButtonWithCodeBehind.Content = "First";
await Task.Factory.StartNew(() => Thread.Sleep());
ButtonWithCodeBehind.Content = "Second";
await Task.Factory.StartNew(() => Thread.Sleep());
ButtonWithCodeBehind.Content = "Third";
}
wait捕获同步上下文,并确保该方法的其余部分已注册为在具有相同上下文的线程上运行的延续。在WPF中,UI线程使用codebehindonclick处理code按钮,因此默认情况下,将负责wait
之后的其余方法调用
您可以通过配置任务上的等待来覆盖此默认行为:
await Task.Factory.StartNew(() =>
Thread.Sleep()).ConfigureAwait(continueOnCapturedContext: false);
但是,您绝对不希望在WPF中执行此操作,因为线程池线程将尝试更新您的UI。唯一需要等待的部分是长时间运行的部分—IO调用,或者在本例中是CPU限制的睡眠
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
ButtonWithCodeBehind.Content = "First";
await Task.Factory.StartNew(() => Thread.Sleep());
ButtonWithCodeBehind.Content = "Second";
await Task.Factory.StartNew(() => Thread.Sleep());
ButtonWithCodeBehind.Content = "Third";
}
wait捕获同步上下文,并确保该方法的其余部分已注册为在具有相同上下文的线程上运行的延续。在WPF中,UI线程使用codebehindonclick处理code按钮,因此默认情况下,将负责wait
之后的其余方法调用
您可以通过配置任务上的等待来覆盖此默认行为:
await Task.Factory.StartNew(() =>
Thread.Sleep()).ConfigureAwait(continueOnCapturedContext: false);
但是,您绝对不希望在WPF中执行此操作,因为线程池线程将尝试更新您的UI。如果您可以将长时间运行的任务拆分为两个不同的长时间运行操作(如上面示例中的两个线程。休眠),则可以单独等待每个长时间运行的任务。因此,UI更新将在UI线程上执行
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
ButtonWithCodeBehind.Content = "First";
await Task.Run(() => Thread.Sleep(1000));
ButtonWithCodeBehind.Content = "Second";
await Task.Run(() => Thread.Sleep(1000));
ButtonWithCodeBehind.Content = "Third";
}
如果您可以将长时间运行的任务拆分为两个不同的长时间运行操作(如上面示例中的两个Thread.Sleeps),那么您可以单独等待每个长时间运行的任务。因此,UI更新将在UI线程上执行
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
ButtonWithCodeBehind.Content = "First";
await Task.Run(() => Thread.Sleep(1000));
ButtonWithCodeBehind.Content = "Second";
await Task.Run(() => Thread.Sleep(1000));
ButtonWithCodeBehind.Content = "Third";
}
模拟工作任务。运行+线程。睡眠正常。对于“等待一点”任务。延迟是一种方式。感谢Andreas,线程。睡眠是因为我当时使用Silverlight,Silverlight不包含任务。延迟:(模拟工作任务。运行+线程。睡眠很好。对于“等待一点”Task.Delay是一个不错的选择谢谢Andreas,线程。睡眠是因为我当时在使用Silverlight,Silverlight不包含任务。Delay:(