从用户界面( thread1 )我想创建进度用户界面( thread2 )。 Progress UI在 thread3 中创建一个任务,并等待其完成。
任务( thread3 )完成并调用必须在 thread2 中执行的进度UI关闭。
对于关闭操作,我使用AsyncOperationManager捕获thread2的上下文,然后从 thread4 执行POST方法。
但是关闭总是发生在另一个线程上。
以下所有代码均来自ProgressWindows类。
_currentTask = new Progress<double>(Close); // I call this in progress UI constructor.
// This is invoked in constructor of Progress class which is used inside ProgressWindow.
_asyncOperation = AsyncOperationManager.CreateOperation(null);
public static void Run2(Action action)
{
Debug.WriteLine(":: Run2 in thread: {0}", Thread.CurrentThread.ManagedThreadId);
var th = new Thread(_ =>
{
Debug.WriteLine(":: StartNew in thread: {0}", Thread.CurrentThread.ManagedThreadId);
var progress = new ProgressWindow();
progress.Run(action);
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
public void Run(Action action)
{
Debug.WriteLine(":: Run in thread: {0}", Thread.CurrentThread.ManagedThreadId);
SetupProgressBar();
RunTask(action);
ShowDialog();
}
private void RunTask(Action action)
{
Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null));
}
private void Close(object state)
{
Debug.WriteLine(":: Close in thread: {0}", Thread.CurrentThread.ManagedThreadId);
Hide();
Close();
}
问题是:
private void RunTask(Action action)
{
Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null));
}
您看,_currentTask.OnCompleted(null)
是从另一个线程调用的,但Progress类型的_currentTask
使用UI线程中捕获的上下文,但始终从UI线程以外的其他线程调用OnCompleted
。为什么?它必须在同一个环境中。
更新1:
将 System.Threading.SynchronizationContex 与 System.Windows.Form.WindowsFormsSynchronizationContext 和 System.Windows.Threading.DispatcherSynchronizationContext
答案 0 :(得分:0)
Synchronization context in asynchronous WCF per call service
AsyncOperationManager 的工作方式不同,具体取决于调用 AsyncOperationManager.CreateOperation 的上下文。 依赖于上下文, AsyncOperationManager.CreateOperation 可能会创建三个上下文:
System.Threading.SynchronizationContext System.Windows.Form.WindowsFormsSynchronizationContext System.Windows.Threading.DispatcherSynchronizationContext
在我的情况下,当我在ShowDialog之前捕获上下文时,我捕获线程同步上下文, 但如果我在OnLoad事件中调用AsyncOperationManager.CreateOperation,我会捕获 System.Windows.Form.WindowsFormsSynchronizationContext或DispatcherSynchronizationContext 取决于使用WindowsForms或WPF。这是错误的来源。
我会将其剪切为仅使用Dispatcher.BeginInvoke。 但是为了将所有代码保留为Progress,我只是放置了AsyncOperationManager.CreateOperation并在ProgressWindow UI的OnLoad中创建了新的后台线程。它解决了这个问题。