在C#中同步包装异步方法

我有一个第三方库,其中包含一个异步执行函数的类。 该类inheritance自Form。 该function基本上基于存储在数据库中的数据执行计算。 完成后,它会在调用表单中调用_Complete事件。

我想要做的是同步调用该函数,但是从非Windows窗体应用程序。 问题是,无论我做什么,我的应用程序块和_Complete事件处理程序永远不会触发。 从Windows窗体我可以通过使用“完整”标志和“while(!complete)application.doevents”来模拟同步运行的函数,但显然application.doevents在非Windows窗体应用程序中不可用。

有什么东西阻止我在Windows窗体应用程序之外使用类的方法(由于它inheritance自’Form’)? 有什么方法可以解决这个问题吗?

谢谢,迈克

在尝试时,可能值得尝试类似下面的内容,使用WaitHandle来阻止当前线程而不是旋转并检查标志。

using System; using System.Threading; class Program { AutoResetEvent _autoEvent; static void Main() { Program p = new Program(); p.RunWidget(); } public Program() { _autoEvent = new AutoResetEvent(false); } public void RunWidget() { ThirdParty widget = new ThirdParty(); widget.Completed += new EventHandler(this.Widget_Completed); widget.DoWork(); // Waits for signal that work is done _autoEvent.WaitOne(); } // Assumes that some kind of args are passed by the event public void Widget_Completed(object sender, EventArgs e) { _autoEvent.Set(); } } 

我有更多关于这个问题的信息(我和mikecamimo在同一个团队工作)。

正确复制时,Windows窗体应用程序中也会出现此问题。 在原始OP中,Windows窗体中没有出现问题,因为没有阻塞。 使用ResetEvent引入阻塞时,会出现同样的问题。

这是因为事件处理程序(Widget_Completed)与调用Widget.DoWork的方法位于同一个线程上。 结果是AutoResetEvent.WaitOne(); 永远阻止因为永远不会调用事件处理程序来设置事件。

在Windows窗体环境中,这可以通过使用Application.DoEvents轮询消息队列并允许处理事件来解决。 见下文。

 using System; using System.Threading; using System.Windows.Forms; class Program { EventArgs data; static void Main() { Program p = new Program(); p.RunWidget(); } public Program() { _autoEvent = new AutoResetEvent(false); } public void RunWidget() { ThirdParty widget = new ThirdParty(); widget.Completed += new EventHandler(this.Widget_Completed); data = null; widget.DoWork(); while (data == null); Application.DoEvents(); // do stuff with the results of DoWork that are contained in EventArgs. } // Assumes that some kind of args are passed by the event public void Widget_Completed(object sender, EventArgs e) { data = e; } } 

在非Windows窗体应用程序(如Windows服务)中,应用程序不可用,因此无法调用DoEvents。

问题是线程和widget之间的问题.DoWork的相关事件处理程序需要在另一个线程上。 这应该可以防止AutoResetEvent.WaitOne无限期地阻塞。 我认为… :)

关于如何实现这一点的任何想法都会很棒。

 AutoResetEvent _autoEvent = new AutoResetEvent(false); public WebBrowser SyncronNavigation(string url) { WebBrowser wb = null; wb = new WebBrowser(); wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted); wb.ScriptErrorsSuppressed = true; wb.Navigate(new Uri(url)); while (!_autoEvent.WaitOne(100)) Application.DoEvents(); return wb; } void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { //throw new NotImplementedException(); _autoEvent.Set(); } 

你有组件的来源吗? 听起来它依赖于它将从WinForms环境调用的事实(必须是一个很好的理由,为什么一个库inheritance自Form!),但很难确定。