8

関数を非同期で実行するクラスを含むサードパーティのライブラリがあります。クラスはフォームから継承します。この関数は基本的に、データベースに保存されているデータに基づいて計算を実行します。終了すると、呼び出しフォームで_Completeイベントを呼び出します。

私がやりたいのは、関数を同期的に呼び出すことですが、Windows以外のフォームアプリケーションから呼び出します。問題は、私が何をしても、アプリケーションがブロックされ、_Completeイベントハンドラーが起動しないことです。Windowsフォームから、「complete」フラグと「while(!complete)application.doevents」を使用して同期的に実行される関数をシミュレートできますが、明らかにapplication.doeventsはWindowsフォーム以外のアプリケーションでは使用できません。

Windowsフォームアプリケーションの外部でクラスのメソッドを使用するのを妨げるものはありますか(「フォーム」から継承しているため)?これを回避する方法はありますか?

ありがとう、マイク

4

4 に答える 4

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();
    }
}
于 2009-01-24T06:46:59.437 に答える
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 に答える
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 を呼び出すことができません。

問題はスレッドの 1 つであり、widget.DoWork に関連付けられたイベント ハンドラーは何らかの方法で別のスレッドにある必要があります。これにより、AutoResetEvent.WaitOne が無期限にブロックされるのを防ぐことができます。おもう... :)

これを達成する方法についてのアイデアは素晴らしいでしょう。

于 2009-01-28T02:47:16.583 に答える
0

コンポーネントのソースはありますか?WinForms環境から呼び出されるという事実に依存しているように聞こえますが(ライブラリがFormから継承するのには十分な理由であるはずです!)、確実に知ることは困難です。

于 2009-01-24T06:32:35.673 に答える