2010-05-04 32 views

Respuesta

13

(simplificación adelante)

Un hilo de interfaz de usuario es un hilo Apartamento roscado único que se utiliza para crear diversos objetos de interfaz de usuario (en Winforms, esto significa Controles). Por convención y regla, se puede acceder a un Control solo desde el hilo que se usó para crearlo; Hacer lo contrario puede y producirá resultados inesperados, desde rarezas visuales hasta un desplome.

A menos que se crea de forma explícita más, no es sólo un hilo de interfaz de usuario dentro de una aplicación de Windows Forms. Mientras puede crear otro hilo y comenzar un ciclo de mensajes, hay muy pocas razones por las que desea hacer esto, y dos hilos de UI diferentes no pueden "hablar" entre sí más de lo que cualquier otro hilo puede hablar con un Hilo de interfaz de usuario.

+2

+1 por mencionar que puede hacer esto, pero que rara vez es la manera en que deberían hacerse las cosas ... –

+0

¿Qué pasa cuando se hace un nuevo Thread(). Start() dentro de un STAThread? –

+0

@Griever: Eso inicia un nuevo hilo, pero está completamente separado del hilo de UI. Hacer un nuevo inicio de subproceso en cualquier lugar crea un nuevo hilo no relacionado. –

0

corregido para la corrección:

Hay un hilo de interfaz de usuario por aplicación activa en Windows Forms y concepto similar para WPF.

es decir: Al iniciar la aplicación, hay un hilo, se convierte en un hilo de interfaz de usuario cuando Application.Run (nueva Form1()); se llama.

Si intenta hacer Application.Run (new Form2()); en tiempo de ejecución obtendrá "System.InvalidOperationException: iniciar un segundo ciclo de mensajes en un solo hilo no es una operación válida. Use Form.ShowDialog en su lugar".

Si realmente necesita dos formularios separados para no compartir el mismo hilo, deberá crear un nuevo hilo, luego llamar a Application.Run (nuevo MyForm()) etc. etc. Esto no es común.

+1

Esto no es cierto. Diferentes formas, en Windows Forms, todas usan el ** mismo ** hilo. La bomba de mensajes los hace receptivos. –

+0

Lo he invertido, los cuadros de diálogo modales requieren un nuevo hilo, los cuadros de diálogo no modal * no requieren * un nuevo hilo. El punto sigue siendo que los hilos normales pueden convertirse en hilos UI cuando se lanza un nuevo formulario desde ellos. – David

+0

Esto aún no es cierto. "Lanzar un formulario" desde un nuevo hilo, sin cuidado especial para iniciar un ciclo de mensajes, causará todo tipo de problemas, incluyendo (en la mayoría de los casos) bloqueos debido a la falta de STA por defecto. –

7

Una interfaz de usuario de hilo tiene una serie de características que lo hacen especial:

  • Windows tiene una cola de mensajes asociado con el hilo. Esto sucede tan pronto como se crea la primera ventana en el hilo.
  • El subproceso ejecuta un bucle de mensaje, lo que permite a Windows enviar mensajes a las ventanas. El bucle de mensajes se crea tan pronto como llame a Application.Run().
  • COM se inicializó en el subproceso, solicitando un apartamento de subproceso único. Se necesita una STA para permitir que muchas características de Windows funcionen correctamente, características que no son seguras para subprocesos por diseño. COM garantiza que estas funciones siempre se llamen de manera segura para la ejecución de subprocesos, clasificando la llamada de un subproceso de trabajo al subproceso STA según sea necesario. Ejemplos de estas características son Arrastrar + Soltar, el portapapeles, los cuadros de diálogo del shell (OpenFileDialog, etc.), los controles ActiveX como WebBrowser, los ganchos de ventana establecidos por SetWindowsHookEx, los proveedores de accesibilidad como los utilizados por un lector de pantalla, los proveedores de automatización de la interfaz de usuario. Todo el código externo, ninguno de ellos seguro para subprocesos.
  • El hilo nunca se bloquea en ninguna operación, se mantiene receptivo para que pueda despachar los mensajes de Windows según sea necesario para mantener la interfaz de usuario receptiva y fluir las solicitudes de cálculo de COM. Por ejemplo, las llamadas a WaitHandle.WaitAny() están explícitamente prohibidas y generan una excepción. El CLR tiene soporte específico para WaitOne() y lock, bombeando un bucle de mensaje interno para evitar interbloqueo.

El hilo de inicio de un proceso casi siempre se selecciona como el hilo de la interfaz de usuario, aunque no es un requisito difícil. El estado STA se selecciona mediante el atributo [STAThread] en el método Principal().

Puede crear un hilo de interfaz de usuario asegurándose de que se cumplan los requisitos anteriores. Eso podría tener este aspecto en una aplicación Windows Forms:

var ui = new Thread(() => { Application.Run(new Form2()); }); 
    ui.SetApartmentState(ApartmentState.STA); 
    ui.Start(); 

que crea una segunda ventana, que se ejecuta en su propio subproceso de interfaz de usuario. Un problema típico que tiene con este arreglo es que ahora tiene dos ventanas separadas, no están asociadas entre sí. La segunda ventana no puede ser propiedad de la 1ra, tiene su propio orden Z independiente de la 1ra. Difícil de tratar por el usuario. El evento SystemEvents.UserPreferenceChanged es notable, inevitablemente activará su evento en el hilo equivocado y es probable que cause un punto muerto. Muchos de los controles de WinForms lo suscriben. Excepto en circunstancias excepcionales, como una pantalla de bienvenida, esto no mejora en absoluto la interfaz de usuario.

+0

Me gusta su respuesta detallada. –

Cuestiones relacionadas