在具有同步上下文的同一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.WindowsFormsSynchronizationContextSystem.Windows.Threading.DispatcherSynchronizaionContext

在具有同步上下文的同一UI线程中完成操作

混合

异步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并创建了新的后台线程。它已经解决了这个问题。