2010-03-12 6 views
5

Mi aplicación WPF está estructurada utilizando el patrón MVVM. Los ViewModels se comunicarán de forma asíncrona con un servidor, y cuando se devuelven los datos solicitados, se activa una devolución de llamada en ViewModel, y hará algo con estos datos. Esto se ejecutará en un hilo que no es el hilo UI. A veces, estas devoluciones de llamadas implican trabajo que debe realizarse en el hilo de UI, por lo que necesito el Dispatcher. Esto podría ser cosas como:¿Se considera una mala práctica que los objetos ViewModel tengan el Dispatcher?

  • Adición de datos a un ObservableCollection
  • comandos de activación Prism que fijarán algo que se mostrarán en la interfaz gráfica de usuario
  • Creación de objetos de WPF de algún tipo.

Intento evitar esto último, pero los dos primeros puntos aquí me parecen razonables para ViewModels. Asi que; ¿está bien que ViewModels mantenga el Dispatcher para poder invocar comandos para el subproceso de UI? ¿O esto se considera una mala práctica? ¿Y por qué?

+0

he tenido que hacer lo mismo en los controladores - el controlador suscribe al evento de carga de la opinión de que crea, y en ese momento agarra una referencia al despachador de la vista. Esto es especialmente útil para ejecutar delegados que han sido pasados ​​por alto. – slugster

+0

¡Gracias por la propina!Estoy usando un contenedor IoC, y el contenedor IoC se creó en App.xaml.cs. Supongo que esto se ejecuta en el subproceso de interfaz de usuario, por lo que el plan es obtener el despachador actual en el punto donde se crea el contenedor de Io y agregarlo al contenedor. Queda para ver si esto es exitoso. – stiank81

+0

Funciona a la perfección. O simplemente puede usar Dispatcher.CurrentDispatcher en cualquier parh que sepa que está siendo ejecutado por el hilo de UI. Como p. los constructores de ViewModel: si se están construyendo en el hilo de UI. – stiank81

Respuesta

3

Desde un ObservableCollection debe ser actualizado en el hilo al que pertenece (suponiendo una aplicación de interfaz gráfica de usuario), y ObservableCollections debe ser parte de la ViewModel, entonces hay un caso claro para el modelo de vista que tiene una Dispatcher.

No puedo verlo como parte del Modelo.

+0

Definitivamente no debe ser parte del modelo. La solución que puede hacer es crear un nuevo ObservableCollection y completar el resultado con esto, pero realmente me suena como un truco. – stiank81

+0

Tengo una pequeña variación de MVVM: Mi modelo es un código no administrado que se ejecuta en subprocesos de trabajo. El modelo vuelve a llamar a mi código .Net, que luego se distribuye en el hilo de la GUI. La función despachada que se ejecuta en el subproceso de GUI luego actualiza ViewModel. De esta manera, mi máquina virtual no necesita saber sobre despacho. – Surfbutler

1

Estoy de acuerdo con kyoryu y me gustaría señalar que solo crea una dependencia en el archivo de ServiceModel (que ya tiene) y no en la propia vista, por lo que hay muy poco para oponerse a esta construcción.

me estaba probando algunas cosas con WPF, un simple máquina virtual y las discusiones de ayer y llegaron a la conclusión de que absolutamente necesitaba para pasar el despachador a la máquina virtual.

Véase también Using WPF UI thread should always ensure STA apartment mode, right?

+0

¡Gracias por su respuesta! Estoy empezando a usar Dispatcher ahora, y realmente simplifica las cosas. Antes de hacerlo, me encontré con soluciones muy creativas (hacky). Utilizando Dispathcer creo que el código está mejorando mucho. Pero supongo que debes ser consciente de lo que haces, no hagas * nada * solo porque puedes .. – stiank81

+0

¿Pasas el Dispatcher a la VM? Probablemente no sea lo que haría. Mi punto era que la VM podría necesitar un Dispatcher porque podría ser propietaria de cosas que necesitan para colocar Dipsatached. Por lo general, me gusta hacer mi envío en el último momento posible. Si esa es la máquina virtual, está bien, si está en la vista, está bien. Si mi vista fuera totalmente xaml, podría estar tentado de que la máquina virtual sea responsable del despachador, solo para mantener la pureza de la vista xaml. Pero eso es probablemente demasiado astuto por m parte. – kyoryu

+0

Por supuesto, esto podría deberse a que en mi trabajo diario estoy trabajando en bits de infraestructura y estamos tratando de tener el contexto del hilo. Y rápidamente llego a la conclusión de que tiene más sentido hacer eso tan cerca a los bits que realmente les importa como sea posible, en lugar de centralizarlo ... – kyoryu

2

Idealmente, un ViewModel debe ser totalmente independiente de la tecnología de interfaz de usuario utilizado. en teoría, debemos ser capaces de volver a utilizarlo para Windows Forms (si proxeneta los Windows Forms controla un poco para apoyar mejor la unión), para páginas Web (preveo algún tipo de mecanismo especial aquí que compilar el ViewModel también en Javascript), y para cualquier tecnología futura. No todas estas tecnologías usarán el modelo Dispatcher.

Dicho esto, considero que es un compromiso pragmático incluir el Dispatcher en el ViewModel en la actualidad. En mi clase base ViewModel, puedo comprobar por la corriente Dispatcher:

protected override void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (Deployment.Current.Dispatcher == null || Deployment.Current.Dispatcher.CheckAccess()) 
     { 
      base.OnPropertyChanged(sender, e); 
     } 
     else 
     { 
      Deployment.Current.Dispatcher.BeginInvoke(() => base.OnPropertyChanged(sender, e)); 
     } 
    } 

todavía tengo la dependencia de System.Windows por supuesto, pero bueno. : ->

+0

Parece bueno poder reutilizar sus ViewModels, pero realmente no estoy de acuerdo en que este sea el objetivo. Solo considere una cosa simple como enlaces de comando. Realmente necesitas enlaces de comando cuando haces MVVM, pero ¿Winforms tiene ICommand? De hecho, no estoy seguro, pero antes quería hacer que mi ViewModels se construyera en Mono, y al menos Mono no tiene ICommand. – stiank81

+0

Aún así, valiosa retroalimentación. +1 – stiank81

+1

@heartmaster, si (realmente) es un objetivo reutilizar su VM, debe ocultar el despachador detrás de alguna interfaz (que también puede ser reimplementada por WinForms InvokeRequired, etc.). –

0

debe considerar el uso AsyncOperation lugar.

Cuestiones relacionadas