在我的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);
为什么会这样?
答案 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";
}));
});
}
}