c# - dispatcher begininvoke
Dispatcher to Thread Relations en WPF (3)
La aplicación WPF tiene 2 hilos (uno para la entrada, el otro para la interfaz de usuario)
Esta afirmación no es del todo correcta. Una aplicación WPF tiene solo un subproceso de UI que maneja toda la interacción de UI y la entrada del usuario. También hay un subproceso "oculto" responsable de la representación, pero normalmente los desarrolladores no lo tratan.
La relación Dispatcher / Thread es de uno a uno, es decir, un Dispatcher siempre se asocia con un thread y se puede usar para enviar ejecuciones a ese thread. Dispatcher.CurrentDispatcher
devuelve el dispatcher para el subproceso actual, es decir, cuando llama a Dispatcher.CurrentDispatcher
en un subproceso de trabajo, obtiene un dispatcher para ese subproceso de trabajo.
Los Dispatchers se crean a pedido, lo que significa que si accede a Dispatcher.CurrentDispatcher
y no hay ningún Dispatcher asociado con el subproceso actual, se creará uno.
Dicho esto, el número de despachadores en la aplicación siempre es menor o igual al número de subprocesos en la aplicación.
No me queda del todo claro cuántos Dispatchers hay en una aplicación y cómo están relacionados o referidos por Threads.
Según tengo entendido, una aplicación WPF tiene 2 subprocesos (uno para entrada y otro para UI) y 1 despachador (asociado a UI-Thread). ¿Qué sucede si creo otro subproceso? Llamémoslo "subproceso de trabajo": cuando llamo a Dispatcher.CurrentDispatcher
en el subproceso de trabajo, ¿qué distribuidor obtendré?
Otro caso: suponga una aplicación de consola con 2 subprocesos: el subproceso principal y un subproceso de entrada. En el hilo principal, primero creo el hilo de entrada y luego llamo Application.Run()
Thread thread = new Thread(new ThreadStart(UserInputThreadFunction));
thread.Start();
Application.Run();
Habrá un despachador, ¿verdad? En el hilo de entrada, ¿Dispatcher.CurrentDispatcher devuelve al despachador del hilo principal? ¿O cuál es la forma correcta de obtener una instancia para el despachador del hilo principal?
¿Podría ser que haya más de un despachador en una aplicación WPF? ¿Hay algún caso, tendría sentido crear otro despachador?
La aplicación WPF por defecto solo tiene un Dispatcher. El distribuidor es el único hilo que le permitirá interactuar con los elementos de la interfaz de usuario. Te abstrae las implementaciones, por lo que solo debes preocuparte por estar en el subproceso de la interfaz de usuario, es decir, el Dispatcher.
Si está intentando interactuar directamente con un elemento visual (por ejemplo, establecer un texto en un cuadro de texto usando txtBkx.Text = "new"
), desde un subproceso de trabajo, tendrá que cambiar a un subproceso de la interfaz de usuario:
Application.Current.Dispatcher.Invoke(
() => { txtBkx.Text = "new"; });
Alternativamente, puede usar SynchronizationContext.Current
(mientras está en un subproceso de la interfaz de usuario) y usarlo para ejecutar delegados en un subproceso de la interfaz de usuario de un subproceso diferente. Como debe tener en cuenta, Dispatcher.CurrentDispatcher
no siempre se puede configurar.
Ahora, de hecho, puede crear diferentes ventanas WPF en la misma aplicación y tener un distribuidor individual para cada ventana:
Thread thread = new Thread(() =>
{
Window1 w = new Window1();
w.Show();
w.Closed += (sender2, e2) =>
w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Como nota al margen, recuerde que en MVVM, puede actualizar el modelo desde un subproceso que no pertenece a la IU y aumentar los eventos modificados de la propiedad desde un subproceso que no pertenece a la IU, ya que WPF organizará los eventos PropertyChanged por usted. Sin embargo, el aumento de CollectionChanged tiene que estar en un hilo de interfaz de usuario.
Un dispatcher siempre está asociado con un subproceso y un subproceso puede tener como máximo un despachador ejecutándose al mismo tiempo. Un hilo no necesita tener un despachador.
Por defecto, solo hay un Dispatcher: para la interfaz de usuario. A veces tiene sentido tener otros despachadores, otras veces no. Un subproceso de envío debe bloquearse en el método Dispatcher.Run()
para poder procesar las invocaciones al distribuidor. Un subproceso como el de entrada de la consola no estará disponible para procesar invocaciones.