我正在编写一个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 Addin,代码看起来像这样:
public class ThisAddin
{
private ApiLogin _loginWorker;
private void ThisAddInStartup(object sender, EventArgs e)
{
_loginWorker = new ApiLogin();
_loginWorker.RunWorkerAsync();
}
}
当我运行我的插件时,由于我在后台工作程序完成事件处理程序中有一个Thread.Sleep(50000),因此我希望outlook可以阻止50秒,但这不会发生。这对我来说意味着这段代码不能在主线程中运行?我一直在寻找一个徒劳的解决方案,现在我想知道这里是否有人知道这可能是什么问题?
答案 0 :(得分:3)
BackgroundWorker需要同步提供程序来确定RunWorkerCompleted事件在哪个线程上运行。它使用SynchronizationContext.Current。插件启动时,此属性为null的可能性非常高。所以什么都没有得到同步,事件在线程池线程上运行。
.NET框架中有两个同步提供程序,分别是Winforms和WPF的一个。他们需要各自的消息循环来执行线程编组,他们在Application.Run()方法中分配SynchronizationContext.Current。你没有。最简单的解决方案是创建Winforms表单并调用其ShowDialog()方法。这本身已经阻止了Outlook用户界面。也很好地向用户提供一些反馈,因此她不必猜测Outlook停止响应的原因。
答案 1 :(得分:1)
我当然希望它在与ThisAddinStartup
方法相同的线程上运行:您可以通过在两个位置跟踪线程ID来验证这一点。
至于Outlook,也许它在一个单独的UI线程上运行你的加载项。