Problema de subprocesos cruzados, BackgroundWorker y ReportProgress

Tengo un [STAThread] principal que contiene algo como esto:

try
{
    // Start the port enumerator.

    Enumerator enumerator = new Enumerator();

    // Display the main window and start everything going.

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new TopViewForm(ref enumerator));
}
catch (Exception)
{
}

El objeto enumerador en sí contiene un subproceso de trabajo en segundo plano. El trabajo de fondo se inicializa así:

MyBackgroundWorker = new BackgroundWorker();
MyBackgroundWorker.WorkerSupportsCancellation = true;
MyBackgroundWorker.WorkerReportsProgress = true;
MyBackgroundWorker.DoWork +=new DoWorkEventHandler(MyBackgroundWorker_DoWork);
MyBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(MyBackgroundWorker_ProgressChanged);
MyBackgroundWorker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(MyBackgroundWorker_RunWorkerCompleted);
MyBackgroundWorker.RunWorkerAsync();

Ahora, para informar el progreso al formulario principal (la instancia de TopViewForm), el subproceso en Enumerator está llamando a ReportProgress con algún objeto de usuario apropiado. ReportProgress, supongo, llegará en forma de evento ProgressChanged y se ejecutará en el subproceso principal de la interfaz de usuario, que es el subproceso en el que se creó el Enumerador (es decir, no el subproceso de BackgroundWorker).

Dado que este es el caso, ¿cómo es posible que obtenga un error de infracción de subprocesos cruzados cuando intento configurar un nodo en un TreeView en el subproceso del proceso principal en respuesta a un evento de este objeto? El ProgresoCambió categóricamente no parecen ejecutarse en el subproceso del proceso principal, observando la pila de llamadas.

Supongo entonces que Application.Run genera un nuevo hilo y ejecuta el formulario con eso. Pero la documentación dice lo contrario. O cometí un error tonto o hay algo que no entiendo aquí.

Alguien tiene alguna opinión?

preguntado el 03 de mayo de 12 a las 15:05

Un Bgw trabaja en estrecha colaboración con Application.Run(), así que muévalo dentro del formulario. -

Bien pensando los dos. Si lo muevo dentro del formulario, funciona bien. -

Bueno, el primero en agregarlo como respuesta obtiene los puntos :) -

2 Respuestas

Creo que el evento de cambio de progreso se está ejecutando antes Application.Run se llama primero. Si no inicia el trabajador en segundo plano desde Main, sino desde dentro de uno de los formularios, estará seguro de que el bucle de mensajes ya existe cuando se crea el trabajador en segundo plano y comienza a informar sobre el progreso.

contestado el 03 de mayo de 12 a las 15:05

BackgroundWorker se basa en un SynchronizationContext actual que se establece para funcionar. El evento ProgressChanged se implementa como Delegado SendOrPostCallback y como se indica en la documentación de msdn, SendOrPostCallback representa un método de devolución de llamada que desea ejecutar cuando se envía un mensaje a un contexto de sincronización. Agregar BackgroundWorker a un formulario en un diseñador de formularios establece SynchronizationContext correctamente. En su caso, BackgroundWorker no tiene SynchronizationContext asignado.

contestado el 03 de mayo de 12 a las 15:05

Ah, esta es la respuesta correcta real. Gracias por la información Volody. - Robinson

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.