2009-11-26 20 views
9

Tengo una aplicación que necesita abrir un cuadro de diálogo desde un botón donde el usuario ingresa cierta información.Abrir el cuadro de diálogo en WPF MVVM

Por el momento lo hago así (que funciona muy bien)

  • El clic de botón genera un comando en el modelo de vista.
  • El ViewModel provoca un evento que el controlador escucha.
  • El controlador trabaja en los detalles de la nueva ventana (es decir, Ver, ViewModel & modelo) y la abre (ShowDialog)
  • Cuando se cierra la ventana del controlador suma el resultado a los EventArgs y vuelve al modelo de vista
  • El ViewModel pasa la información al Modelo.

Hay muchos pasos, pero todos tienen sentido y no hay mucho tipeo.

El código es el siguiente (la ventana de pregunta por el nombre del usuario)

modelo de vista:

AskUserNameCommand = DelegateCommand(AskUserNameExecute); 
... 

public event EventHandler<AskUserEventArgs> AskUserName; 

void AskUserNameExecute(object arg) { 
    var e = new AskUserNameEventArgs(); 
    AskUserName(this, e); 
    mModel.SetUserName(e.UserName); 
} 

controlador:

mViewModel.AskUserName += (sender,e) => { 
    var view = container.Resolve<IAskUserNameView>(); 
    var model = container.Resolve<IAskUserNameModel>(); 
    var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model); 
    if (dlg.ShowDialog() ?? false) 
     e.UserName = model.UserName; 
} 

Mi pregunta es cómo la comunicación horizontal trabaja en el Patrón MVVM. De alguna manera, parece incorrecto dejar que el controlador se involucre en la transferencia de datos entre los modelos.

He examinado el patrón del mediador para permitir que los modelos se comuniquen directamente. No me gusta esa idea ya que hace que el modelo dependa de los detalles de las implementaciones de la GUI. (es decir, si el cuadro de diálogo se reemplaza por un cuadro de texto, el modelo debe cambiar)

+1

¿Tuvo un vistazo a las siguientes preguntas http: //stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm http://stackoverflow.com/questions/ 1667888/wpf-mvvm-dialog-example http: // stackoverflow.com/preguntas/1792814/uso-MVVM-cimientos-messenger-a-show-diálogo – Guge

+0

Sí miré pero todos ellos recomiendan un patrón de difusión para resolver algo que es un caso al otro. – adrianm

+0

'El clic del botón genera un comando en ViewModel.', ¿Qué significa esto? 'The ViewModel plantea un evento que el controlador escucha', ¿qué controlador ?! –

Respuesta

0

Me he encontrado con problemas similares. Así es como los he resuelto y por qué he hecho lo que he hecho.

Mi solución:

Mi MainWindowViewModel tiene una propiedad de tipo ModalViewModelBase llama modal. Si mi código necesita cierta vista para ser modal, pone una referencia en esta propiedad. MainWindowView observa esta propiedad a través del mecanismo INotifyPropertyChanged. Si Modal se establece en alguna VM, la clase MainWindowView tomará la VM y la colocará en una ventana de ModalView donde se mostrará el UserControl apropiado a través de la magia de DataTemplates, la ventana se muestra usando ShowDialog. ModalViewModelBase tiene una propiedad para DialogResult y una propiedad llamada IsFinished. Cuando IsFinished se establece en true por la VM modal, la vista se cierra.

También tengo algunos trucos especiales para hacer cosas interactivas como esta de los hilos de Backgroundworker que quieren pedirle al usuario su opinión.

Mi razonamiento:

El principio de puntos de vista modal es que otros puntos de vista están desactivadas, mientras que se muestra la modal. Esto es parte de la lógica de la Vista que es esencialmente sin apariencia. Es por eso que tengo una propiedad para él en MainWindowViewModel. Si tuviera que llevarlo más lejos, debería hacer que cada otra propiedad o comando para todas las otras máquinas virtuales en la máquina virtual principal arroje excepciones, mientras que en el modo modal, pero siento que esto es excesivo.

The View mecanismo de la realidad negando al usuario cualquier otra acción, no tiene que ser realizada con una ventana emergente y ShowDialog, podría ser que se pone el punto de vista modal en la ventana existente, pero anula todos los demás, o alguna otra cosa. Esta lógica relacionada con la vista pertenece a la vista en sí misma. (Que un diseñador típico no pueda codificar esta lógica, parece una preocupación secundaria. Todos necesitamos ayuda algunas veces.)

Así es como lo he hecho. Lo ofrezco solo como sugerencia, probablemente haya otras maneras de pensarlo, y espero que usted obtenga más respuestas también.

+0

Esa es una forma interesante pero yo no digo cómo funciona la transferencia de datos. ¿Cómo se obtiene la entrada del usuario del Modelo de Diálogo (Ver) al Modelo Principal (Vista) cuando se cierra el diálogo? – adrianm

+0

El MainViewModel todavía tiene una referencia a la DialogViewModel después de la vista de diálogo está cerrada. – Guge

+0

bien, eso es más o menos lo mismo que hago, pero lo hace en el modelo de vista. – adrianm

0

He usado EventAggregator de Prism v2 en situaciones similares. Lo bueno de los prims es que no tienes que usar framework completo en tu aplicación MVVM. Puede extraer la funcionalidad EventAggregator y usarla junto con su configuración actual.

+0

El EventAggregator es agradable pero es un servicio de difusión. No puedo encontrar una manera fácil de configurarlo para llamar a una instancia específica de un oyente. Supongamos que el usuario abre el cuadro de diálogo, lo cierra y lo vuelve a abrir. Ahora tengo dos instancias de view/viewmodel/model que escuchan el evento hasta que el GC comience a limpiar. Esto se puede resolver si el oyente darse de baja del evento, sino que conduce a algún tipo de patrón IDisposable en el modelo de vista/modelo. – adrianm

+0

@adrianm estás en lo correcto. Si desea que su mensaje se entregue a una instancia específica, el Agregador de eventos no es apropiado. –

12

No me gusta la mayor parte de las sugerencias actuales por una razón u otra, por lo que pensé que iba a unir a una pregunta con respuestas casi idénticas I hacer como:

Open File Dialog MVVM

Específicamente la respuesta por Cameron MacFarland es exactamente lo que hago. Un servicio proporcionado a través de una interfaz para proporcionar IO y/o la interacción del usuario es el camino a seguir aquí, por las siguientes razones:

  • Es comprobable
  • Se abstrae la implementación de los cuadros de diálogo para que su estrategia para el manejo de este tipo de cosas se puede cambiar sin afectar código constituyente
  • no se basa en los patrones de comunicación. Muchas de las sugerencias que ve por ahí dependen de un mediador, como el Agregador de eventos. Estas soluciones se basan en la implementación de una comunicación bidireccional con los socios del otro lado del mediador, que es difícil de implementar y un contrato muy flexible.
  • ViewModels permanecen autónomos. Yo, como usted, no me siento bien dada la comunicación entre el controlador y ViewModel. El ViewModel debe seguir siendo autónomo si por ninguna otra razón esto facilita la capacidad de prueba.

Espero que esto ayude.

+0

Gracias, eso me hizo pensar. No quiero inyectar el ioc-container en el viewmodel, así que probablemente crearé algún tipo de IControllerService que el viewmodel pueda llamar. Será mucho más limpio que la comunicación basada en eventos que obtuve ahora. – adrianm

+0

Si está utilizando la COI, me acaba de declarar algo así como su IDialogService como dependencia. Normalmente pienso en la IoC como un catálogo de servicios disponibles para todos los objetos constituyentes. –

2

uso el enfoque this para los diálogos con mvvm.

todo lo que tengo que hacer ahora es llamar al siguiente de mi modelo de vista para trabajar con un cuadro de diálogo.

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM); 
Cuestiones relacionadas