c# - the - ¿Cómo puedo configurar un hilo de trabajador de fondo en Single Thread Apartment?
ui thread c# (5)
¡Usé la idea de + Conrad de Wet y funcionó de maravilla!
Sin embargo, hay un pequeño problema con ese código, debe cerrar "this.Invoke ....." como con a});
Aquí está el código de Conrad de Wet con esta solución:
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork);
bgw.RunWorkerAsync();>
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// Invoke the UI thread
// "this" is referring to the Form1, or what ever your form is
this.Invoke((MethodInvoker)delegate
{
Clipboard.GetText();
// etc etc
});
}
Estoy creando una aplicación de prueba automatizada. En esta parte de la aplicación, estoy trabajando en un servidor de sondeo. Funciona al sondear constantemente el servidor web para determinar cuándo debe ejecutarse una nueva prueba automatizada (para ejecuciones automáticas nocturnas de nuestra aplicación GUI).
Cuando el servidor de sondeo ve una solicitud, descarga toda la información necesaria y luego ejecuta la ejecución de prueba en un trabajador de segundo plano. El problema es que parte de la ejecución de prueba tiene OLE, COM y otras llamadas (por ejemplo, Clipboard.Clear()
) que se producen en el subproceso de trabajo en segundo plano. Cuando se produce una de estas llamadas, se produce la siguiente excepción:
El subproceso actual debe establecerse en el modo de apartamento de subproceso único (STA) antes de poder realizar llamadas OLE. Asegúrese de que su función principal tenga marcado STAThreadAttribute.
¿Cómo puedo marcar un hilo de trabajador de fondo como apartamento de hilo único? La llamada principal en mi Program.cs obviamente ya tiene ese atributo.
BackgroundWorker utiliza por defecto un hilo ThreadPool, pero puede anular este comportamiento. Primero necesita definir un SynchronizationContext personalizado:
public class MySynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
Thread t = new Thread(d.Invoke);
t.SetApartmentState(ApartmentState.STA);
t.Start(state);
}
}
Y anule el SynchronizationContext predeterminado, así, antes de usar su BackgroundWorker:
AsyncOperationManager.SynchronizationContext = new MySynchronizationContext();
NOTA: esto puede tener efectos de rendimiento en el resto de la aplicación, por lo que es posible que desee restringir la nueva implementación de publicación (por ejemplo, utilizando los parámetros de estado o d ).
Esto no es posible, BGW usa una cadena de subprocesos. Los hilos TP siempre son MTA, no se pueden cambiar. Deberá utilizar un hilo común, llamar a SetApartmentState () antes de iniciarlo. Este hilo también debería bombear un bucle de mensaje, llame a Application.Run ().
Tal vez deberías considerar llamar a este código desde el hilo de UI. Porque con toda probabilidad, el servidor COM está ejecutando sus métodos en el subproceso de IU de todos modos. Las llamadas de Marshaling desde un subproceso de trabajo al subproceso STA que creó el servidor COM son automáticas, COM se encarga de ello.
O toma el toro por los cuernos y mariscal tú mismo. Puede crear su propio hilo STA para darle al servidor un hogar feliz. Encontrará el código en esta publicación , asegúrese de crear el objeto COM en su sobrescritura Initialize ().
No lo he probado, pero si invocas el Formulario WinForms, deberías volver al hilo de UI y la mayoría de las cosas deberían funcionar de nuevo.
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork);
bgw.RunWorkerAsync();
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// Invoke the UI thread
// "this" is referring to the Form1, or what ever your form is
this.Invoke((MethodInvoker)delegate
{
Clipboard.GetText();
// etc etc
});
}
Normalmente lo configura definiendo attributre [STAThread()]
en el punto de entrada (por ejemplo Static Main).