我有一个第三方库,其中包含一个异步执行函数的类。该类继承自Form。该功能基本上基于存储在数据库中的数据执行计算。完成后,它会在调用表单中调用_Complete事件。
我想要做的是同步调用该函数,但是从非Windows窗体应用程序调用。问题是,无论我做什么,我的应用程序块和_Complete事件处理程序永远不会触发。从Windows窗体我可以通过使用“完整”标志和“while(!complete)application.doevents”来模拟同步运行的函数,但显然application.doevents在非Windows窗体应用程序中不可用。
是否有什么东西可以阻止我在Windows窗体应用程序之外使用类的方法(因为它继承自'Form')? 有什么方法可以解决这个问题吗?
谢谢, 麦克
答案 0 :(得分:8)
尝试使用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();
}
}
答案 1 :(得分:1)
我有更多关于这个问题的信息(我和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无限期地阻塞。我想...... :)
关于如何实现这一目标的任何想法都会很棒。
答案 2 :(得分:1)
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();
}
答案 3 :(得分:0)
您是否拥有该组件的来源?听起来它依赖于它将从WinForms环境调用的事实(必须是一个很好的理由,为什么一个库继承自Form!),但很难确定。