8

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

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

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

谢谢,迈克

4

4 回答 4

8

在 stab 中,可能值得尝试以下类似的方法,它使用 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();
    }
}
于 2009-01-24T06:46:59.437 回答
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 无限期地阻塞。我认为... :)

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

于 2009-01-28T02:47:16.583 回答
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();
}
于 2012-10-01T14:11:36.877 回答
0

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

于 2009-01-24T06:32:35.673 回答