2009-01-24 20 views
7

Mam bibliotekę innej firmy zawierającą klasę, która wykonuje funkcję asynchronicznie. Klasa dziedziczy po formularzu. Funkcja w zasadzie wykonuje obliczenia na podstawie danych przechowywanych w bazie danych. Po zakończeniu wywołuje zdarzenie _Complete w formularzu wywołującym.Jednoczesne zawijanie metody asynchronicznej w języku C#

Co chcę zrobić, to wywołać funkcję synchronicznie, ale z aplikacji bez systemu Windows. Problem polega na tym, że bez względu na to, co robię, moje bloki aplikacji i program obsługi zdarzeń _Complete nigdy nie są uruchamiane. Z postaci okna mogę symulować funkcję działającą synchronicznie za pomocą flagi "complete" i "while (! Complete) application.doevents", ale oczywiście application.doevents nie jest dostępna w aplikacji bez systemu Windows.

Czy istnieje coś, co by mnie zatrzymać stosując metodę klasa poza granicami aplikacji formularza okien (ze względu na to dziedziczenie z Postać)? Czy jest jakiś sposób mogę obejść to?

Dzięki Mike

+0

nie jestem jasne. Czy twój kod działa poprawnie, gdy działa on asynchronicznie w aplikacji bez systemu Windows? Czy może zawsze blokować w nieskończoność w aplikacji non windows? – Sam

+0

W aplikacji bez systemu Windows blokuje się w nieskończoność, ponieważ zdarzenie _Complete nigdy nie jest uruchamiane, mimo próby ręcznego wywołania programu naprawczego itp. W aplikacji formularza systemu Windows działa poprawnie. – mikecamimo

Odpowiedz

0

Czy masz źródło dla komponentu? Wygląda na to, że polega on na tym, że zostanie wywołany ze środowiska WinForms (musi to być dobry powód, dla którego biblioteka dziedziczy z Form!), Ale trudno to stwierdzić.

8

Na stab może warto spróbować czegoś podobnego następujących składników, które wykorzystuje WaitHandle zablokować bieżącego wątku zamiast przędzenia i sprawdzanie flagę.

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(); 
    } 
} 
+0

Myślę, że zrobił to tylko w wiązce testowej WinForms (która działała), myślę, że problem polega na tym, że operacja nigdy się nie kończy, gdy nie ma jej w aplikacji WinForm, więc nie będzie miało znaczenia jak na nią czekać, jeśli nigdy nie będzie dokończenie :) –

+0

Podejrzewam, że tak być może, ale wciąż warto wskazać technikę. Nigdy nie wiesz. :) – Kev

+1

Pewnie .. jedna osoba mniej siedząca w pętli, która wbita w CPU bez powodu jest dobra :-D –

1

Mam więcej informacji na temat tego problemu (pracuję w tym samym zespole co mikecamimo).

Problem występuje również w aplikacji Windows Forms, gdy jest poprawnie replikowany. W oryginalnym OP problem nie pojawił się w postaci okna, ponieważ nie było blokowania. Gdy blokowanie jest wprowadzane przy użyciu elementu ResetEvent, występuje ten sam problem.

Jest tak, ponieważ procedury obsługi zdarzeń (Widget_Completed) znajduje się na tej samej nici, co w sposobie wywołującego Widget.DoWork. Wynik AutoResetEvent.WaitOne(); blokuje na zawsze, ponieważ moduł obsługi zdarzenia nigdy nie jest wywoływany w Ustaw zdarzenia.

W środowisku Windows Forms może to obejść stosując Application.DoEvents odpytywanie kolejki komunikatów i pozwalają przypadku gdy być obsłużone. Zobacz poniżej.

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; 
    } 
} 

W niebędącego Windows Forms aplikacji, takich jak usługa systemu Windows, aplikacja nie jest dostępna tak DoEvents nie można nazwać.

Problem jest jednym z gwintem i że wiąże obsługi zdarzeń widget.DoWork jakoś musi znajdować się na innym wątku. To powinno uniemożliwić AutoResetEvent.WaitOne blokowanie w nieskończoność. Myślę, że ... :)

Wszelkie pomysły na to, jak to osiągnąć, będą fantastyczne.

+0

Znam to dawno temu, ale możesz spróbować uruchomić kod strony trzeciej w innym wątku, tj. Jawnie uruchamiając nowy wątek, aby go uruchomić. W ten sposób WaitOne będzie blokował inny wątek, a zdarzenie Zakończone (powinien) strzelać. – Schmuli

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(); 
} 
Powiązane problemy