为什么内部任务不执行?

时间:2014-09-20 16:20:46

标签: c# wpf multithreading task

在我的wpf应用程序中,我知道我应该更新主线程上的UI元素。我所做的是使用主窗口调度程序来执行此操作。我只是好奇,看看为什么这段代码不起作用:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Loaded += MainWindow_Loaded;            
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            Console.Write("test");

            Task.Factory.StartNew(() =>
            {
                // why does this code does not execute!! ???
                Thread.Sleep(1000);
                txt.Text = "Testing";
            }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

        });                      
    }
}

为什么内部任务不执行?换句话说,我的程序永远不会到达行Thread.Sleep(1000);为什么会这样?

2 个答案:

答案 0 :(得分:3)

当调用线程上没有同步上下文时,TaskScheduler.FromCurrentSynchronizationContext()可能会抛出InvalidOperationException,即SynchronizationContext.Current返回null。

因此,为了捕获UI TaskScheduler,您应该更早地获得它:

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew(() =>
    {
        Console.Write("test");

        Task.Factory.StartNew(() =>
        {
            Thread.Sleep(1000);
            txt.Text = "Testing";
        }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

    });                      
}

您还可以使用延续任务,并在您需要的主题上运行它:

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew(() =>
    {
        Console.Write("test");
    }).ContinueWith(() =>
        {
            Thread.Sleep(1000);
            txt.Text = "Testing";
        }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}

答案 1 :(得分:0)

您可以直接使用调度程序:

public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
      this.Loaded += MainWindow_Loaded;
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
      Task.Factory.StartNew(() =>
      {
        Console.Write("test");
        Thread.Sleep(1000);

        Application.Current.Dispatcher.BeginInvoke(
          DispatcherPriority.Normal, new Action(() => 
          {
            txt.Text = "Testing";
          }));
      });
    }
  }