wpf - dispatcher.invoke c#
¿WPF Dispatcher es la solución de problemas de subprocesamiento múltiple? (2)
El problema principal con el uso del Dispatcher (o BackgroundWorker) es que es difícil de probar, a menos que el arnés de prueba tenga realmente un subproceso de interfaz de usuario.
Solución 1
Use el SynchronizationContext . Proporciona la misma capacidad para invocar en el hilo de la interfaz de usuario y funciona en Windows o WPF. Probando también es posible .
Solución 2
Piense en el despachador como un servicio más. Al usar PRISM, está familiarizado con los servicios y el IOC. Así es como se puede usar dicho servicio:
// Not a UI component
public class MyDomainService : IMyDomainService
{
private readonly IDispatcher _dispatcher;
public MyDomainService(IDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
private void GotResultFromBackgroundThread()
{
_dispatcher.Dispatch(() => DoStuffOnForegroundThread());
}
}
Esto le permite sustituir en diferentes implementaciones su plataforma / prueba.
Aquí hay un ejemplo de IDispatcher , una implementación de WPF y una implementación de prueba . Los registraría en su contenedor de IOC como cualquier otro servicio, y estarán disponibles tanto para la IU como para otros servicios.
Tengo una muy mala sensación sobre el uso de bloqueo en mi código, pero ahora existe el Dispatcher de WindowBase y quiero usarlo en todas partes.
Por ejemplo, utilizo un servicio WCF singleton de múltiples hilos que publica eventos en el EventAggregator de PRISM, la carga útil es inmutable (solo son datos) y cada hilo con un despachador puede recuperar el evento con gracia, sin interbloqueo en su propio despachador. (No solo el subproceso de la interfaz de usuario, sino también los subprocesos con llamadas a la base de datos, los subprocesos con llamada de servicios, los subprocesos que registran u otros subprocesos con llamadas lentas, porque no quiero congelar la UI).
Pero mi problema es que este Dispatcher está acoplado con WPF, así que me siento un poco culpable cuando lo uso en todas partes. Siento que el despachador no fue creado para mi caso de uso en mente.
¿Existe otra implementación de Dispatcher no acoplada con WPF? ¿o está bien abusar de eso?
Gracias,
Actualizar
La solución que me da Paul Stovell es crear una interfaz IDispatcher y un adaptador para Wpf Dispatcher, ¡así que será más fácil de probar! Esta solución fue buena para mí porque refactoreé mis pruebas y ahora puedo usar SynchronousDispatcherAdapter en mis pruebas (gracias a eso, no tengo que usar Dispatcher de WPF en mis pruebas).
Usar el Dispatcher en lugar de un BackgroundWorker tiene sentido, porque estoy usando un patrón de editor / suscriptor múltiple (con PRISM), y gracias al Dispatcher se llama a cada controlador de eventos a los hilos que los suscriben al evento. Esto significa que el único punto en el que puede suceder el problema del multi-threading es en la carga útil de mi evento (lo hice inmutable).
Mis diferentes hilos no se comunican directamente entre ellos, solo pueden publicar y suscribirse al evento. Por lo tanto, las llamadas a bases de datos, registros de llamadas, llamadas de servicios, llamadas de interfaz de usuario se ejecutan en diferentes hilos y no se conocen unos a otros (solo conocen los eventos que suscriben y publican).
El trabajador de segundo plano tendrá sentido, cuando haga algunas llamadas desde mi UI a un repositorio.
Pero espero encontrar un diseño sin usar BackgroundWorker porque prefiero usar este patrón de suscriptor / editor (creo que hace que mi código sea más legible)
sí y no ... es una cosa de representación ... no es una cosa enhebrada per se ...
El despachador selecciona elementos de trabajo con prioridad y ejecuta cada uno hasta su finalización. Cada subproceso de UI debe tener al menos un Dispatcher, y cada Dispatcher puede ejecutar elementos de trabajo en exactamente un subproceso. según este este enlace de Microsoft.
Aún debe manejar por su cuenta los hilos que inicie usted mismo.
Verifique esto para obtener información sobre: Programación multiproceso con el patrón asincrónico basado en eventos
Personalmente uso el Background Worker para mis necesidades de subprocesamiento.