在具有同步上下文的同一UI线程中完成操作
本文关键字:线程 UI 操作 同步 上下文 | 更新日期: 2023-09-27 18:26:49
从UI(thread1)我想创建一个进度UI(
thread2。Progress UI在thread3中创建一个任务并等待其完成。
任务(thread3)完成并调用必须在hread2中执行的进度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线程中捕获的上下文,但OnCompleted
始终是从UI线程以外的另一线程调用的。为什么?它必须在相同的上下文中。
更新1:
将System.Threading.SynchronizationContext与System.Windows.Form.WindowsFormsSynchronizationContext和System.Windows.Threading.DispatcherSynchronizaionContext
异步WCF中每个调用服务的同步上下文
强制WCF使用单线程
AsyncOperationManager的工作方式不同,具体取决于调用异步操作管理器.CreateOperation时的上下文。拒绝上下文,AsyncOperationManager.CreateOperation可以创建三个上下文:
System.Threading.SynchronizationContextSystem.Windows.Form.WindowsFormsSynchronizationContext System.Windows.Threading.DispatcherSynchronizationContext
在我的情况下,当我在ShowDialog之前捕获上下文时,我捕获线程同步上下文,但是,如果我在OnLoad事件中调用AsyncOperationManager.CreateOperation,我将捕获System.Windows.Form.WindowsFormsSynchronizationContext或DispatcherSynchronization上下文取决于使用WindowsForms或WPF。这就是错误的根源。
我会把它简化为只使用Dispatcher.BeginInvoke。但为了让所有的代码都有Progress,我只是在ProgressWindow UI的OnLoad中放置了AsyncOperationManager.CreateOperation并创建了新的后台线程。它已经解决了这个问题。