2014-09-20 3 views
0

В моем приложении wpf я знаю, что должен обновлять элементы пользовательского интерфейса в основном потоке. Я использую диспетчер главного окна, чтобы сделать это. Я просто интересуюсь, почему этот код не работает:Почему внутренняя задача не выполняется?

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); Почему это?

+0

Вы уверены, что не выполнили? Проблема может быть здесь 'txt.Text =« Тестирование »;' это не будет работать, поскольку вы не находитесь в потоке пользовательского интерфейса. Замените его записью или сделайте точку останова, чтобы проверить – thumbmunkeys

+0

Я никогда не попадал в точку останова. Да, я уверен, что она не выполняется. Я просто задаю этот вопрос, чтобы узнать больше о задачах ... –

+0

Возможный дубликат [обновить интерфейс в Task с помощью TaskScheduler.FromCurrentSynchronizationContext] (http://stackoverflow.com/questions/17418208/update-ui-in-task-using -taskscheduler-fromcurrentsynchronizationcontext) – thumbmunkeys

ответ

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); 
} 
0

You может использовать диспетчер напрямую:

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"; 
      })); 
     }); 
    } 
    }