我正在为 Outlook 编写一个插件,其中包含一些用于 API 调用的网络代码,这就是为什么我有几个扩展 BackgroundWorker 类的类,每个类都封装了一个 API 调用。 Api 调用的代码如下所示:
public class ApiLogin : BackgroundWorker
{
private void ThisAddInStartup(object sender, EventArgs e)
{
this.DoWork += BgWorkerDoWork;
this.RunWorkerCompleted += BgWorkerCompleted;
}
private void BgWorkerDoWork(object sender, DoWorkEventArgs e)
{
//Perform network call on the background thread
var logged_in = ApiRequests.login();
e.Result = logged_in;
}
//This should run in the main thread, no?
private void BgWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var logged_in = (bool)e.Result;
//Do stuff in main thread, hopefully..
//Investigate if this runs in the main thread since it should block Outlook, no?
Thread.Sleep(50000);
}
}
对于我的 Outlook 插件,代码如下所示:
public class ThisAddin
{
private ApiLogin _loginWorker;
private void ThisAddInStartup(object sender, EventArgs e)
{
_loginWorker = new ApiLogin();
_loginWorker.RunWorkerAsync();
}
}
当我运行我的插件时,我预计 Outlook 会阻塞 50 秒,因为我在后台工作完成事件处理程序中有一个 Thread.Sleep(50000),但这不会发生。这对我来说意味着这段代码不在主线程中运行?我一直在徒劳地寻找解决方案,现在我想知道这里是否有人知道可能是什么问题?
最佳答案
BackgroundWorker 需要同步提供程序来确定 RunWorkerCompleted 事件在哪个线程上运行。它使用 SynchronizationContext.Current。当您的插件启动时,该属性为空的可能性非常高。因此,没有任何内容同步,并且事件在线程池线程上运行。
.NET 框架中有两种同步提供程序,分别是一种用于 Winforms 的同步提供程序和一种用于 WPF 的同步提供程序。它们需要各自的消息循环来进行线程编码(marshal),它们在 Application.Run() 方法中分配 SynchronizationContext.Current。你两者都没有。最简单的解决方案是创建一个 Winforms 窗体并调用其 ShowDialog() 方法。这本身就已经阻止了 Outlook 用户界面。向用户提供一些反馈也很好,这样她就不必猜测 Outlook 停止响应的原因。
关于c# - BackgroundWorker Completed 似乎没有在主线程中运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7360764/