ändert - So blockieren Sie, bis ein Ereignis in c#ausgelöst wird




c# subscribe to event (3)

Nachdem ich diese Frage gestellt habe , frage ich mich, ob es möglich ist zu warten, bis ein Ereignis ausgelöst wird, und dann die Ereignisdaten abzurufen und einen Teil davon zurückzugeben. So ungefähr:

private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();

Bitte vergewissern Sie sich, dass die von Ihnen angegebene Lösung den Wert direkt zurückgibt und nicht von etwas anderem. Ich frage, ob die obige Methode in irgendeiner Weise verfügbar ist. Ich weiß über Auto / ManuelResetEvent, aber ich weiß nicht, dass sie den Wert direkt zurückgeben, wie ich oben getan habe.

Update: Ich habe ein Ereignis mit MyEventHandler (das ein Message enthält) deklariert. Ich habe eine Methode in einem anderen Thread namens ReadLine wartet, dass das Ereignis ReadLine . Wenn das Ereignis die WaitForValue-Methode auslöst (Teil der Ereignisbehandlungsszene), werden die Ereignisargumente zurückgegeben, die die Nachricht enthalten. Die Nachricht wird dann von ReadLine an das zurückgegeben, was sie auch genannt hat.

Die akzeptierte Antwort auf diese Frage war, was ich getan habe, aber es fühlt sich einfach nicht richtig an. Es fühlt sich fast so an, als könnte etwas zwischen den Daten zwischen der Auslösung von ManuelResetEvent und dem Abrufen und Zurückgeben der Daten durch das Programm passieren.

Update: Das Hauptproblem mit dem Auto/ManualResetEvent ist, dass es zu anfällig ist. Ein Thread könnte auf das Ereignis warten und ihm dann nicht genügend Zeit geben, um es zu ändern, bevor es zu etwas anderem geändert wird. Gibt es eine Möglichkeit, Schlösser oder etwas anderes zu benutzen? Vielleicht mit Get und Set-Anweisungen.


Eine sehr einfache Art von Ereignis, auf das Sie warten können, ist das ManualResetEvent und noch besser das ManualResetEventSlim .

Sie haben eine WaitOne() -Methode, die genau das tut. Sie können ewig warten oder ein Zeitlimit setzen oder ein "Storno-Token", mit dem Sie aufhören können, auf das Ereignis zu warten (wenn Sie Ihre Arbeit abbrechen möchten oder Ihre App zum Beenden aufgefordert wird).

Sie feuern sie, indem sie Set() aufrufen.

Here ist das Dokument.


Sie können ManualResetEvent verwenden. Setzen Sie das Ereignis zurück, bevor Sie den sekundären Thread auslösen, und verwenden Sie dann die WaitOne () - Methode, um den aktuellen Thread zu blockieren. Sie können dann den sekundären Thread das ManualResetEvent setzen lassen, was dazu führen würde, dass der Haupt-Thread fortgesetzt wird. Etwas wie das:

ManualResetEvent oSignalEvent = new ManualResetEvent(false);

void SecondThread(){
    //DoStuff
    oSignalEvent.Set();
}

void Main(){
    //DoStuff
    //Call second thread
    System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
    oSecondThread.Start();

    oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
    oSignalEvent.Reset();
    //Do more stuff
}

Wenn die aktuelle Methode asynchron ist, können Sie TaskCompletionSource verwenden. Erstellen Sie ein Feld, auf das der Ereignishandler und die aktuelle Methode zugreifen können.

    TaskCompletionSource<bool> tcs = null;

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        tcs = new TaskCompletionSource<bool>();
        await tcs.Task;
        WelcomeTitle.Text = "Finished work";
    }

    private void Button_Click2(object sender, RoutedEventArgs e)
    {
        tcs?.TrySetResult(true);
    }

In diesem Beispiel wird ein Formular mit einem Text namens WelcomeTitle und zwei Schaltflächen verwendet. Wenn auf die erste Schaltfläche geklickt wird, wird das Klickereignis gestartet, es wird jedoch an der Wartezeile angehalten. Wenn Sie auf die zweite Schaltfläche klicken, wird die Aufgabe abgeschlossen und der WelcomeTitle-Text wird aktualisiert. Wenn Sie auch eine Zeitüberschreitung wünschen, ändern Sie sie

await tcs.Task;

zu

await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
    WelcomeTitle.Text = "Task Completed";
else
    WelcomeTitle.Text = "Task Timed Out";






events