Cómo evitar la referencia circular en MVVM cuando se usa DispatcherObject.Dispatcher

El siguiente código está muy simplificado. Estoy tratando de abstraer un contexto de despachador para que mis modelos de vista puedan sincronizar eventos que solo se pueden generar en el subproceso de la GUI.

Hay una referencia circular en este patrón. ¿Hay alguna otra forma de crear un DispatcherObject? ¿Lo estoy haciendo mal?

He leído otras preguntas como esta, pero todas las respuestas parecen implicar una referencia a la DispatcherObject en la ViewModel. ¿Es este un lugar aceptable para una referencia circular?

class ViewModel {
    public DispatcherObject Dispatcher { get; set; }
}

class ModelView : UserControl {

    ModelView() {
        InitializeComponent();
        DataContext = new ViewModel { Dispatcher = this };
    }
}

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

3 Respuestas

En términos generales, las referencias circulares son algo que desea evitar. Aquí hay dos alternativas:

1. Coge el despachador estáticamente

El enfoque rápido y sucio. Muy fácil de hacer, funcionará bien casi todo el tiempo, pero como cualquier otra cosa que se haga de forma estática, no se presta a la verificación (lo que puede o no ser un problema). En el raro caso de que su aplicación WPF tenga más de un subproceso de interfaz de usuario, no podrá usar este enfoque a ciegas.

WPF: var dispatcher = Application.Current.Dispatcher;

Luz plateada: var dispatcher = Deployment.Current.Dispatcher;

2. Hacer que el despachador dependa de ViewModel

Configure su contenedor de inyección de dependencia apropiadamente y tenga la Dispatcher ser una dependencia para aquellos ViewModels que necesitan acceder a él. Este enfoque es más complicado, pero le permite trabajar con varios subprocesos de interfaz de usuario, es comprobable y, en general, tiene todas las ventajas y desventajas habituales de hacer cosas con DI.

contestado el 04 de mayo de 12 a las 08:05

Gracias. Elegí un enfoque que es una especie de combinación de los dos. ViewModel toma un Dispatcher definido estáticamente, y esa instancia estática puede ser actualizada por la aplicación, prueba unitaria, lo que sea. - ken

También hice otra pregunta sobre las diferencias entre Application.Current.Dispatcher y Dispatcher.CurrentDispatcher: stackoverflow.com/questions/10448987/… - ken

No es necesario obtener el despachador específico del control. Puede enviar directamente a través de la implementación, es decir, Deployment.Current.Dispatcher.BeginInvoke(()=>something).

Por lo general, no proporciono el objeto de despachador, sino un delegado de acción. Luego puede probar sin saltar subprocesos haciendo que la acción se ejecute, mientras que en producción puede invocarse en Dispatcher.

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

Gracias por la respuesta, pero parece que la clase de implementación es solo para Silverlight. - ken

Esto me llevó a un concepto similar disponible en WPF: Dispatcher.CurrentDispatcher. msdn.microsoft.com/en-us/library/… - ken

¿Por qué mantener una referencia a la DispatcherObject cuando lo que realmente necesita para invocar es el propio despachador?

class ViewModel {
    public Dispatcher Dispatcher { get; set; } }

class ModelView : UserControl {

    ModelView() {
        InitializeComponent();
        DataContext = new ViewModel { Dispatcher = Dispatcher };
    } }

contestado el 04 de mayo de 12 a las 09:05

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