Caliburn Micro - coroutines - UI线程意外阻止

时间:2013-07-10 18:22:35

标签: wpf multithreading caliburn.micro coroutine

我使用Caliburn Micro的协同程序进行工作流程,同时显示WPF中的屏幕。

我为忙碌屏幕制作了这个IDisposable构造:围绕一个长时间运行的作业包装一个using语句,并在该作业期间显示一个忙碌的屏幕。当使用块结束时,Dispose()将隐藏幕后的忙碌屏幕。

使用范围构造使用..

显示和隐藏繁忙的屏幕
Application.Current.Dispatcher.Invoke(...show/hide form...)

..让它在UI线程上发生:

使用示例:

yield return new TaskResult(Task.Factory.StartNew(() =>
{
  using (_dialogController.ShowDialogForUsingScope(new BusyViewModel() 
                       { Message = "Account gegevens ophalen..." }))
  {
     _securityContext.RefreshAccountFromServer();
  }
  using (_dialogController.ShowDialogForUsingScope(new BusyViewModel() 
                       { Message = "You see me..." }))
  {
     _securityContext.RefreshAccountFromServer();
  }
}));

这非常有效:繁忙的屏幕显示,工作已完成,已被删除,在第二个工作期间紧接着另一个忙碌的屏幕并完成:)

但是当我用2个yield返回时,第二个作业仍在UI线程上运行:

Debug.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", IsBackground: " + Thread.CurrentThread.IsBackground);
yield return new TaskResult(Task.Factory.StartNew(() =>
{
    Debug.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", IsBackground: " + Thread.CurrentThread.IsBackground);
    using (_dialogController.ShowDialogForUsingScope(new BusyViewModel() { Message = "Account gegevens ophalen..." }, 2000))
    {
        _securityContext.RefreshAccountFromServer();
    }
}));
Debug.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", IsBackground: " + Thread.CurrentThread.IsBackground);
yield return new TaskResult(Task.Factory.StartNew(() =>
{
    Debug.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", IsBackground: " + Thread.CurrentThread.IsBackground);
    using (_dialogController.ShowDialogForUsingScope(new BusyViewModel() { Message = "You never see me..." }, 2000))
    {
    }
}));

导致:

Thread: 9, IsBackground: False
Thread: 12, IsBackground: True
Thread: 9, IsBackground: False
Thread: 9, IsBackground: False --> 9 too ?? 

这解释了为什么它会冻结,但为什么这个任务不在另一个线程上呢?

1 个答案:

答案 0 :(得分:2)

在谷歌搜索后,我找到了这个彻底的答案:

Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?

似乎任务调度程序在某些情况下试图在请求线程中运行任务(在我的情况下在UI线程中是同步的)。

为防止这种情况,您需要在启动任务时传递默认调度程序,而不是Current(这是默认行为):

示例:

yield return new TaskResult(Task.Factory.StartNew(() =>
            {
                using (_dialogController.ShowDialogForUsingScope(new BusyViewModel() { Message = "Inloggen..." }, 800))
                {
                    // do stuff
                }
            }, 
            CancellationToken.None, 
            TaskCreationOptions.None, 
            TaskScheduler.Default));