sincrónico sincronico sincronica que entre ejemplos ejemplo diferencias comunicacion await async asincronico asincronica aprendizaje c# asynchronous wrapper synchronous

sincronico - Envolviendo un método asincrónico sincrónicamente en C#



sincronico y asincronico (4)

¿Tiene la fuente del componente? Parece que se basa en el hecho de que se llamará desde un entorno WinForms (debe ser una buena razón por la que una biblioteca hereda de Form!), Pero es difícil saberlo con certeza.

Tengo una biblioteca de terceros que contiene una clase que realiza una función de forma asincrónica. La clase hereda del formulario. La función básicamente realiza un cálculo basado en datos almacenados en una base de datos. Una vez que ha finalizado, llama a un evento _Complete en el formulario de llamada.

Lo que me gustaría hacer es llamar a la función de forma sincrónica, pero desde una aplicación de formulario que no sea Windows. El problema es que, sin importar lo que haga, mis bloques de aplicaciones y el controlador de eventos _Complete nunca se activan. Desde un formulario de Windows, puedo simular la función ejecutando sincrónicamente usando un indicador "completo" y un "while (! Complete) application.doevents", pero obviamente application.doevents no está disponible en una aplicación de formulario que no sea Windows.

¿Hay algo que me impida usar el método de la clase fuera de una aplicación de formulario de Windows (debido a que hereda de ''Formulario'')? ¿Hay alguna manera de que pueda evitar esto?

Gracias, Mike


En una puñalada, podría valer la pena intentar algo como lo siguiente que utiliza un WaitHandle para bloquear el hilo actual en lugar de girar y comprobar un indicador.

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


Tengo más información sobre este problema (estoy trabajando en el mismo equipo que mikecamimo).

El problema también ocurre en la aplicación Windows Forms, cuando se replica correctamente. En el OP original, el problema no ocurría en el formulario de Windows porque no había bloqueo. Cuando se introduce el bloqueo mediante el uso de un ResetEvent, ocurre el mismo problema.

Esto se debe a que el controlador de eventos (Widget_completado) está en el mismo hilo que el método que llama a Widget.DoWork. El resultado es que AutoResetEvent.WaitOne (); bloquea para siempre porque nunca se llama al controlador de eventos para establecer el evento.

En un entorno de formularios de Windows esto puede solucionarse utilizando Application.DoEvents para sondear la cola de mensajes y permitir que se maneje el evento. Vea abajo.

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

En una aplicación que no sea Windows, como un servicio de Windows, la aplicación no está disponible, por lo que DoEvents no se puede llamar.

El problema es uno de threading y ese widget. El controlador de eventos asociado de DoWork de alguna manera tiene que estar en otro hilo. Esto debería evitar que AutoResetEvent.WaitOne bloquee indefinidamente. Creo... :)

Cualquier idea sobre cómo lograr esto sería fantástica.


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