Синхронное завершение асинхронного метода в C # - PullRequest
7 голосов
/ 24 января 2009

У меня есть сторонняя библиотека, содержащая класс, который выполняет функцию асинхронно. Класс наследуется от формы. Функция в основном выполняет вычисления на основе данных, хранящихся в базе данных. По завершении он вызывает событие _Complete в вызывающей форме.

То, что я хотел бы сделать, это вызвать функцию синхронно, но из приложения не из окна. Проблема заключается в том, что независимо от того, что я делаю, блоки моего приложения и обработчик событий _Complete никогда не срабатывают. Из формы Windows я могу смоделировать функцию, выполняющуюся синхронно, используя флаг «complete» и «while (! Complete) application.doevents», но очевидно, что application.doevents недоступен в приложении не из окна.

Есть ли что-то, что мешало бы мне использовать метод класса вне приложения Windows Form (из-за его наследования от 'Form')? Есть ли способ, как я могу обойти это?

Спасибо, Mike

Ответы [ 4 ]

8 голосов
/ 24 января 2009

При ударе, возможно, стоит попробовать что-то вроде следующего, которое использует 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 голос
/ 01 октября 2012
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();
}
1 голос
/ 28 января 2009

У меня есть больше информации по этой проблеме (я работаю в той же команде, что и mikecamimo).

Проблема также возникает в приложении Windows Forms при правильной репликации. В оригинальном OP проблема не возникала в форме окна, потому что не было никакой блокировки. Когда блокировка вводится с помощью 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 Form, таком как служба Windows, приложение недоступно, поэтому DoEvents не может быть вызвано.

Проблема заключается в потоке и в том, что обработчик событий, связанный с виджетом. DoWork должен каким-то образом находиться в другом потоке. Это должно предотвратить блокировку AutoResetEvent.WaitOne на неопределенный срок. Я думаю ...:)

Любые идеи о том, как этого добиться, были бы фантастическими.

0 голосов
/ 24 января 2009

У вас есть источник для компонента? Похоже, он полагается на тот факт, что он будет вызываться из среды WinForms (это должно быть веской причиной, по которой библиотека наследуется от Form!), Но это трудно точно знать.

...