【问题标题】:TaskScheduler.FromCurrentSynchronizationContext block uiTaskScheduler.FromCurrentSynchronizationContext 块 ui
【发布时间】:2013-04-09 23:59:18
【问题描述】:

我有这个 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。
我希望我可以看到程序计数到 10,但我看到的不是它,而是在 TextBlock 中 10 秒和 10 秒后被阻止的 UI

我该如何解决?

【问题讨论】:

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


    【解决方案1】:

    您在 CountToTen 函数中使用了阻塞调用 Wait。要解决此问题,您需要改用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());
    }
    

    【讨论】:

    • 出现编译错误。但是,当我在没有 TaskScheduler.FromCurrentSynchronizationContext() (并删除 Seconds.Text = ...)的情况下使用此代码时,这并不重要
    • 错误 2 'await' 运算符只能在异步 lambda 表达式中使用。考虑用 'async' 修饰符标记这个 lambda 表达式。 D:\TestProjects\TestCloseWindow\TestCloseWindow\MainWindow.xaml.cs 33 21 TestCloseWindow
    • @takayoshi - 抱歉。现在看看。
    • @chuex 根本不需要新任务;这只是不必要的代码膨胀。
    【解决方案2】:

    通过使用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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多