2010-01-21 12 views
6
  • Las colecciones que están enlazadas en una vista WPF deben actualizarse en el hilo de la interfaz de usuario.
  • ViewModel expone una colección
  • Por lo tanto, cuando recogida en el modelo de vista es modificado hay que hacerlo en el hilo de interfaz de usuario
  • La mejor práctica es mantener ViewModels ignorantes de vista y, presumiblemente, tales detalles como despachador.

¿Cuál es la forma más limpia de resolver esto mientras se mantiene el modelo de vista comprobable?UI Threading con ViewModels

Respuesta

1

Tienes razón en que WPF nos da un Dispatcher para hacer multi-threading simple; pero si desea separar las preocupaciones con el patrón de MVVM, deberá implementar una estrategia de subprocesamiento diferente.

Siempre he encontrado la clase BackgroundWorker más que suficiente para satisfacer este, empujando actualizaciones de vuelta al hilo de interfaz de usuario, de tal manera que se puede actualizar el ObservableCollection en la máquina virtual y tener cambios se propagan a la vista.

3

Una opción aquí es exponer un SynchronizationContext utilizable dentro del ViewModel. Este es el mecanismo que usa la clase BackgroundWorker para sincronizarse con la interfaz de usuario sin introducir una dependencia en WPF o Windows Forms, y permitiéndole trabajar con múltiples tecnologías.

Esto le permitiría volver al enlace de la interfaz de usuario sin hacer referencia a la interfaz de usuario en sí, incluido el Dispatcher.

+0

No es una mala idea, pero me pregunto acerca de la flexibilidad de SyncContext, las implicaciones de tomar una dependencia de ella, etc ... ¿Alguna idea? – Schneider

+0

Tiene un poco de "mínimo denominador común", pero Send() y Post() proporcionan la funcionalidad necesaria, y no fuerza una dependencia en ningún marco específico. Como mencioné, así es como BackgroundWorker puede funcionar con WPF + Win FOrms sin una dependencia. –

0

Una opción es crear una subclase de ObservableCollection que anule OnPropertyChanged y OnCollectionChanged y distribuya los eventos apropiados de vuelta al subproceso de la interfaz de usuario (a través de algo como SynchronizationContext).

Esto permite que ViewModel sea más agnóstico cuando se trata de subprocesos, también hace que el código bajo prueba sea mucho más fácil de administrar.

+0

Soy consciente de las soluciones generales a este problema ... mi pregunta es específicamente sobre MVVM y el conjunto mantiene el ViewModel libre de este tipo de cosas. Hasta el momento parece que la VM necesita tener conocimiento de Sync/Threading – Schneider

+0

Exactamente, no podrá eliminar por completo el conocimiento de threading del ViewModel. Pero puede ser "oculto" por un ViewModel base y una subclase de ObservableCollection. Al hacer esto, el ViewModel (ViewAccountsViewModel, por ejemplo) será independiente del subprocesamiento y, por lo tanto, mucho más comprobable. –

1

Esto se soluciona bastante bien abstrayendo toda su lógica de agregar/eliminar/actualizar colecciones observables + cualquier otra lógica compleja que ocurra en su escenario en diferentes subprocesos.

Esta clase de controlador puede ser responsable de actualizar ViewModel (puede tener una referencia a la VM por la interfaz) en el hilo correcto.

+1

¿Le gustaría dar un ejemplo más detallado? – Schneider

+0

Difícil de hacer en Stack Overflow. Puedes imaginar una clase de controlador que tenga toda la interacción compleja con el modelo. Como propiedad de este controlador, es el ViewModel para el enlace.El controlador puede reaccionar a datos en diferentes subprocesos, alinearse con el subproceso de interfaz de usuario y luego establecer propiedades en ViewModel ya que tiene una referencia. También, los comandos ejecutados en ViewModel pueden propagarse a través de eventos al controlador, para que empuje la acción a otro hilo (si es necesario) –

+1

No hay muchos ejemplos de tales ModelViewViewModelController en la web, pero parece que tiene potencial – Schneider