TaskScheduler.FromCurrentSynchronizationContext块ui

时间:2013-03-28 13:23:46

标签: c# wpf task-parallel-library async-await c#-5.0

我有这个xaml

<Window x:Class="TestCloseWindow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="500" Height="400">
<StackPanel>
    <TextBlock x:Name="Seconds"></TextBlock>
    <Button Content="fasdfd" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Window>

这段代码

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
         await CountToTen();
    }

    private Task CountToTen()
    {
       return Task.Factory.StartNew
              (() =>
                  {
                      for (var i = 1; i <= 10; i++)
                      {
                        Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
                        Task.Delay(1000).Wait();
                      }
                   }
                   , CancellationToken.None
                   , TaskCreationOptions.None
                   , TaskScheduler.FromCurrentSynchronizationContext()
              );
    }
}

在此代码中,我使用TaskScheduler.FromCurrentSynchronizationContext()来从后台任务访问UI。
我希望我能看到程序计数到十,但不是它,我看到阻止的UI 10秒和TextBlock中的10后

我该如何解决?

2 个答案:

答案 0 :(得分:2)

您在Wait功能中使用了阻止来电CountToTen。要解决此问题,您需要使用await。这也需要一些其他的改变。

async private Task CountToTen()
{
    await Task.Factory.StartNew( async () =>
        {
            for (var i = 1; i <= 10; i++)
            {
                Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
                //Task.Delay(1000).Wait();
                await Task.Delay(1000);
            }
        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

答案 1 :(得分:0)

StartNewTaskScheduler.FromCurrentSynchronizationContext()一起使用,在这种特殊情况下,您根本就没有做任何事情。由于整个任务将在UI线程中运行,因此它与在线执行它没有什么不同。

问题的主要来源是Task.Delay(1000).Wait();。您正在进行阻塞等待一秒钟,而您正在从UI线程进行。您可以重构代码以不执行阻塞等待,还可以删除不必要的任务创建。这就是你所需要的:

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    for (var i = 1; i <= 10; i++)
    {
        Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
        await Task.Delay(1000)
    }
}