2009-03-17 18 views
9

Tengo una aplicación MVVM. En uno de los ViewModels está el 'FindFilesCommand' que rellena un ObservableCollection. Luego implemento un 'RemoveFilesCommand' en el mismo ViewModel. Este comando abre una ventana para obtener más información del usuario.El mejor lugar para abrir una nueva ventana en Model View ViewModel

¿Dónde/cuál es la mejor manera de hacer esto mientras se mantiene el paradigma de MVVM? De alguna manera haciendo:

new WhateverWindow().Show()

en el modelo de vista parece mal.

Saludos,

Steve

+0

He respondido una pregunta muy similar en [esta publicación] (http://stackoverflow.com/a/15512972/385995). –

Respuesta

2

Personalmente, considero este escenario como uno en el que el modelo de vista de ventana principal desea mostrar una tarea para que el usuario final complete.

Debería ser responsable de crear la tarea e inicializarla. La vista debe ser responsable de crear y mostrar la ventana secundaria y usar la tarea como el modelo de vista de la ventana recién instanciada.

La tarea se puede cancelar o confirmar. Se genera una notificación cuando se completa.

La ventana utiliza la notificación para cerrarse. El modelo de vista principal usa la notificación para realizar un trabajo adicional una vez que la tarea se ha confirmado si el seguimiento funciona.

Creo que esto es lo más cercano a lo natural/intuitivo que hacen las personas con su enfoque de código subyacente, pero refactorizado para dividir las preocupaciones independientes de UI en un modelo de vista, sin introducir gastos generales adicionales tales como servicios, etc.

Tengo una implementación de esto para Silverlight. Ver http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspx para más detalles ... Me encantaría escuchar comentarios/más sugerencias sobre esto.

-1

para los diálogos de este tipo. Lo defino como una clase anidada de FindFilesCommand. Si el diálogo básico utilizado entre muchos comandos lo defino en un módulo accesible para esos comandos y tengo el comando, configuro el diálogo en consecuencia.

Los objetos de comando son suficientes para mostrar cómo el diálogo está interactuando con el resto del software. En mi propio software, los objetos Command residen en sus propias bibliotecas, por lo que los diálogos están ocultos del resto del sistema.

Hacer algo más elegante es exagerado en mi opinión. Además, tratar de mantenerlo al más alto nivel a menudo implica la creación de muchas interfaces adicionales y métodos de registro. Es una gran cantidad de codificación para obtener poca ganancia.

Al igual que con cualquier marco de esclavitud, la devoción lo llevará por algunas callejuelas extrañas. Debe usar el juicio para ver si hay otras técnicas para usar cuando huele mal el código. De nuevo, en mi opinión, los diálogos deben estar estrechamente vinculados y definidos al lado del comando que los usa. De esa manera, cinco años después puedo volver a esa sección del código y ver todo lo que ese comando está tratando.

De nuevo, en las pocas instancias en que un diálogo es útil para múltiples comandos, lo defino en un módulo común a todos ellos. Sin embargo, en mi software tal vez 1 de cada 20 diálogos es así. La principal excepción es el diálogo de abrir/guardar archivo. Si docenas de comandos utilizan un cuadro de diálogo, yo iría por la ruta completa de definir una interfaz, crear un formulario para implementar esa interfaz y registrar ese formulario.

Si la localización para uso internacional es importante para su aplicación, deberá asegurarse de que cuenta con este esquema, ya que todos los formularios no están en un solo módulo.

+0

Hola. Creo que tener diálogos concretos en ViewModel rompería la capacidad de prueba. –

0

Me he encontrado con este problema con MVVM también. Mi primer pensamiento es tratar de encontrar una forma de no usar el diálogo. Usando WPF es mucho más fácil encontrar una forma más sencilla de hacer las cosas que con un diálogo.

Cuando eso no es posible, la mejor opción parece ser que ViewModel llame a una clase Shared para obtener la información del usuario. El ViewModel debe ignorar por completo que se está mostrando un cuadro de diálogo.

Por lo tanto, como ejemplo simple, si necesitara que el usuario confirme una eliminación, ViewModel podría llamar a DialogHelper.ConfirmDeletion(), que devolvería un booleano de si el usuario dijo sí o no. La muestra real del diálogo se haría en la clase de Ayuda.

Para cuadros de diálogo más avanzados, devolviendo muchos datos, el método de ayuda debe devolver un objeto con toda la información del diálogo en él.

Estoy de acuerdo en que no es el ajuste más suave con el resto de MVVM, pero aún no he encontrado ejemplos mejores.

+0

llamando a "DialogHelper.ConfirmDeletion()" de realmente llamar al cuadro de diálogo no hace ninguna deferencia imho. Todavía estás mezclando UI pura en el código. (después de todo, DialogHelper ya sugiere que es un ayudante de ventana ...) –

+0

Estoy de acuerdo, pero no veo ninguna manera mejor de hacer esto. El cuadro de diálogo debe mostrarse desde ViewModel para que funcione. Creo que tener ViewModel al menos no mostrar explícitamente el diálogo es un buen paso, sin embargo. De esta forma, los diálogos se pueden reutilizar y reemplazar de manera convincente con un esfuerzo mínimo. – timothymcgrath

+0

Estoy pensando que quizás los eventos podrían ser el camino a seguir. Sin embargo, aún no estoy seguro de los detalles y cómo encajaría con el MVVM puro. –

0

Tengo que decir que los servicios son el camino a seguir aquí.

La interfaz de servicio proporciona una forma de devolver los datos. Entonces, la implementación real de ese servicio puede mostrar un diálogo o lo que sea para obtener la información necesaria en la interfaz.

De esta manera para probar esto, puede burlarse de la interfaz de servicio en sus pruebas, y el ViewModel no es el más acertado. En lo que se refiere a ViewModel, solicitó a un servicio cierta información y recibió lo que necesitaba.

+0

Hola. ¿Quién sería el dueño del servicio? La vista o el modelo? No parece estar bien en ninguno de esos lugares. –

+0

¿Qué quiere decir con quién es el propietario del servicio? Es un singleton. Además, si piensas en lo que proporciona el servicio, es la VM la que lo llama porque es lo que necesita para confirmar la eliminación, etc. –

+0

Disculpa, quise decir "en qué espacio de nombres vive la interfaz del servicio". –

1

En el ejemplo de bienes raíces Southridge de Jaime Rodríguez y Karl Shifflet, están creando la ventana en el modelo de vista, más específicamente en la parte ejecutar un comando de cota:

protected void OnShowDetails (object param) 
    { 
     // DetailsWindow window = new DetailsWindow(); 
     ListingDetailsWindow window = new ListingDetailsWindow(); 
     window.DataContext = new ListingDetailsViewModel (param as Listing, this.CurrentProfile) ; 
     ViewManager.Current.ShowWindow(window, true); 
    } 

Aquí está el enlace: http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx

Supongo que no es un gran problema. Después de todo, Viewmodel actúa como el "pegamento" entre la vista y la capa empresarial/capa de datos, por lo que es normal estar acoplado a la Vista (UI) ...

+0

Gracias por la respuesta. ¿No significaría esto que ViewModel tiene una referencia a View para ListingDetailsWindow (y también ViewManager?). –

+1

No, un ViewModel idealmente debería ser independiente de la tecnología UI. Claro que es pegamento, pero debe evitar cualquier dependencia en una vista concreta y, si es posible, cualquier dependencia en cosas concretas de UI/mecánica. – Falcon

1

Onyx (http://www.codeplex.com/wpfonyx) proporcionará un buena solución para esto. A modo de ejemplo, mirar el servicio ICommonDialogProvider, que puede ser utilizado desde un modelo de vista así:

ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>(); 
IOpenFileDialog openDialog = provider.CreateOpenFileDialog(); 
// configure the IOpenFileDialog here... removed for brevity 
openDialog.ShowDialog(); 

Esto es muy similar al uso de la OpenFileDialog concreto, pero es totalmente comprobable. La cantidad de desacoplamiento que realmente necesita sería un detalle de implementación para usted. Por ejemplo, en su caso, es posible que desee un servicio que oculte por completo el hecho de que está utilizando un cuadro de diálogo. Algo a lo largo de las líneas de:

public interface IRemoveFiles 
{ 
    string[] GetFilesToRemove(); 
} 

IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>(); 
string[] files = removeFiles.GetFilesToRemove(); 

A continuación, tiene que asegurarse de la vista tiene una implementación para el servicio IRemoveFiles, para lo cual hay varias opciones disponibles para usted.

Onyx aún no está listo para su lanzamiento, pero el código funciona completamente y se puede utilizar al menos como punto de referencia. Espero liberar estabilizar la interfaz V1 muy pronto, y se lanzará tan pronto como tengamos documentación y muestras decentes.

+0

Hola. El 'this.View.GetService()': ¿Qué devuelve this.View return y necesitaría una referencia específica a cualquiera de los tipos en mi espacio de visualización 'view'? Para mí, eso parecería inicialmente romper MVVM. Cuidado, podría estar equivocado. Soy muy nuevo. –

+0

Devuelve una instancia de View, parte del framework Onyx. View es un IServiceProvider y también proporciona acceso al ViewElement (el elemento al que está asociada la Vista), como DependencyObject. Si nunca usas ViewElement, no estás violando los principios de MVVM. Mira la muestra simple. – wekempf

0

Lo que estamos haciendo es somethng así, lo que se describe aquí: http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx

El modelo de vista tiene una propiedad que se llama ConfirmDeletionViewModel. Tan pronto como establezco la Propiedad, el Comportamiento abre el diálogo (modal o no) y usa ConfirmDeletionViewModel. Además, estoy pasando un delegado que se ejecuta cuando el usuario quiere cerrar el diálogo. Esto es básicamente un delegado que establece la propiedad ConfirmDeletionViewModel en nulo.

Cuestiones relacionadas