visual tutorial the studio example event delegate custom and c# events

tutorial - subscribe to the event c#



Cómo bloquear hasta que se active un evento en c# (4)

Después de hacer esta pregunta , me pregunto si es posible esperar a que se dispare un evento, y luego obtener los datos del evento y devolver parte del mismo. Más o menos así:

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

Asegúrese de que la solución que proporcione devuelva el valor directamente en lugar de obtenerlo de otra forma. Pregunto si el método anterior está disponible de alguna manera. Sé de Auto / ManuelResetEvent, pero no sé si devuelven el valor directamente como lo hice anteriormente.

Actualización: He declarado un evento usando MyEventHandler (que contiene un campo de Message ). Tengo un método en otro hilo llamado ReadLine esperando que el evento se dispare. Cuando el evento activa el método WaitForValue (parte de la escena de manejo de eventos) devuelve los eventos args, que contienen el mensaje. A continuación, ReadLine devuelve el mensaje a lo que lo llamó.

La respuesta aceptada a esa pregunta que hice fue lo que hice, pero simplemente no me siento bien. Casi parece que algo podría pasarle a los datos entre la activación ManuelResetEvent y el programa que recupera los datos y los devuelve.

Actualización: el principal problema con el Auto/ManualResetEvent es que es demasiado vulnerable. Un hilo podría esperar el evento y luego no dar tiempo suficiente para que nadie lo obtenga antes de cambiarlo a otra cosa. ¿Hay alguna manera de usar bloqueos o algo más? Tal vez usando declaraciones get y set.


Puede usar ManualResetEvent. Restablezca el evento antes de disparar el hilo secundario y luego use el método WaitOne () para bloquear el hilo actual. A continuación, puede configurar el hilo secundario para configurar el evento ManualResetEvent, lo que provocaría que el hilo principal continuara. Algo como esto:

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 }


Si el método actual es asíncrono, puede usar TaskCompletionSource. Cree un campo al que puedan acceder el controlador de eventos y el método actual.

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

Este ejemplo utiliza un formulario que tiene un bloque de texto llamado WelcomeTitle y dos botones. Cuando se hace clic en el primer botón, se inicia el evento de clic pero se detiene en la línea de espera. Cuando se hace clic en el segundo botón, la tarea se completa y el texto de WelcomeTitle se actualiza. Si también desea tiempo de espera, cambie

await tcs.Task;

a

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


Si está contento de utilizar las extensiones reactivas de Microsoft, esto puede funcionar muy bien:

public class Foo { public delegate void MyEventHandler(object source, MessageEventArgs args); public event MyEventHandler _event; public string ReadLine() { return Observable .FromEventPattern<MyEventHandler, MessageEventArgs>( h => this._event += h, h => this._event -= h) .Select(ep => ep.EventArgs.Message) .First(); } public void SendLine(string message) { _event(this, new MessageEventArgs() { Message = message }); } } public class MessageEventArgs : EventArgs { public string Message; }

Puedo usarlo así:

var foo = new Foo(); ThreadPoolScheduler.Instance .Schedule( TimeSpan.FromSeconds(5.0), () => foo.SendLine("Bar!")); var resp = foo.ReadLine(); Console.WriteLine(resp);

Necesitaba llamar al mensaje SendLine en un hilo diferente para evitar el bloqueo, pero este código muestra que funciona como se esperaba.


Un tipo muy fácil de evento que puede esperar es el ManualResetEvent , y aún mejor, el ManualResetEventSlim .

Tienen un método WaitOne() que hace exactamente eso. Puedes esperar por siempre, o establecer un tiempo de espera, o un "token de cancelación", que es una forma de que decidas dejar de esperar el evento (si deseas cancelar tu trabajo o se te pide que salgas).

Los disparas llamando a Set() .

Here está el documento.