wpf mvvm view viewmodel childwindow

Usando MVVM en WPF, ¿debería lanzar ventanas secundarias desde el código de Vista detrás, o ViewModel?



childwindow (6)

Me he sentido desconcertado por esto por un tiempo. Estoy escribiendo una aplicación RibbonWindow WPF bastante grande usando el patrón MVVM. La pantalla tiene un menú RibbonBar en la parte superior y el resto muestra las distintas Vistas. Algunas Vistas contienen otras Vistas y algunas de ellas tienen botones que inician Windows.

Hasta ahora, he estado haciendo esto desde View code behind file, pero soy consciente de que se supone que estos archivos están vacíos cuando se usa MVVM. Podría mover el código de inicio de la ventana secundaria al ViewModel, pero luego necesitaría una referencia al RibbonWindow principal (para establecerlo como el propietario de la ventana secundaria) y eso no parece correcto.

Cualquier consejo o consejo sobre cómo esto se logra normalmente utilizando MVVM sería muy apreciado.


Bueno, una observación para empezar es que "no tener ningún código en absoluto en el código subyacente" es en realidad un "mito". Si quieres ser pragmático, y ves que tener algún código (lo menos posible sería mejor) te facilitará la vida y resolverá tu problema, entonces deberías ir con eso.

Sin embargo, en esta situación, en realidad hay algunas formas poco flexibles de hacer esto. Podría tener un servicio que haga la interacción por usted. Usted inicia la interacción con el usuario desde ViewModel, el servicio se encarga de eso (al mostrar una ChildWindow por ejemplo) y le devuelve la respuesta del usuario. Ese servicio se puede burlar para probarlo fácilmente. Y puede ser probado por separado.

Es decir, si quieres hacer las cosas tú mismo. Si desea un marco que haga el trabajo pesado por usted, puede verificar la funcionalidad InteractionRequest que ofrece Prism . Aquí está el artículo de MSDN que habla sobre escenarios avanzados de MVVM que incluye una sección sobre patrones de interacción del usuario . Así es como lo hago, y es bastante simple, elegante y directo.

Espero que esto ayude :)


En esta situación, View debe manejar la apertura de las ventanas secundarias. Sin embargo, ViewModel podría impulsar la creación de las ventanas, pero llamar a View para crear un nuevo Windows. Esto salvará la lógica del patrón MVVM: ViewModel tiene los "cerebros" pero no está involucrado en una creación de ventana particular.


Normalmente me encargo de esto creando algún tipo de WindowViewLoaderService. Cuando su programa se inicializa, registra sus Window''s y sus ViewModels con un código como este:

WindowViewLoaderService.Register(TypeOf(MainWindowView), TypeOf(MainWindowViewModel); WindowViewLoaderService.Register(TypeOf(MyWindowView), TypeOf(MyWindowViewModel);

Luego, cuando puede, por ejemplo, llamar a este servicio desde su ViewModel y todo lo que debe hacer referencia es su otro ViewModel. Por ejemplo, si está en su MainWindowViewModel, puede tener un código como este:

var myChildWindowVM = new MyWindowViewModel(); WindowViewLoaderService.ShowWindow(myChildWindowVM)

El WindowViewLoaderService buscaría qué Vista está asociada con el ViewModel especificado que le pasó. Creará esa Vista, establecerá su DataContext en el ViewModel que pasó, y luego mostrará la Vista.

De esta manera, sus modelos de vista nunca saben sobre ninguna vista.

Puede transferir uno de estos servicios con bastante facilidad. Todo lo que necesita hacer es mantener un Dictionary con la clave siendo su ViewModelType y el valor siendo su ViewType. El método Register se agrega a su diccionario y el método ShowWindow busca la vista correcta según el ViewModel pasado, crea la vista, establece el DataContext y luego llama a Show en él.

La mayoría de los marcos MVVM proporcionan algo como esto para ti de la caja. Por ejemplo, Caliburn tiene una elegante que solo usa la convención de nomenclatura, se llama ViewLocator en este Framework. Aquí hay un enlace que resume: http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx

Cinch, por otro lado, lo llama WPFUIVisualizerService, que se puede ver en acción aquí: http://www.codeproject.com/KB/WPF/CinchIII.aspx

Esto debería ayudarlo a avanzar.


Para llevar la respuesta de Matt un paso más allá, puede hacer que todas las vistas sean un control del usuario. Luego, cree un ViewContainer, que es una ventana con sus plantillas de datos (como describió).

Luego, solo envía el modelo de vista que desea abrir al servicio de ventana, que establece el DataContext. El servicio luego abriría la ventana y el control de contenido resolverá la vista correcta para el modelo de vista.

Esto significa que todo el registro se realiza en XAML y el servicio de ventanas simplemente sabe cómo hacer eso ... abrir y cerrar ventanas.


Esta es una publicación anterior, pero tal vez esto ayude a alguien en el camino: utilizo MVVM y elevo eventos para abrir ventanas secundarias desde ViewModel a la Vista. El único código detrás es manejar el evento, abrir la ventana, configurar el propietario de la ventana secundaria y eso es todo. En el modelo de vista, si el manejador de eventos es nulo, no está suscrito a la vista y no se dispara. La VM no sabe sobre la vista. El código es bastante simple también y solo toma unas pocas líneas.


ViewModel solo se usa para presentar el estado del sistema y la lógica de UI. Un modelo de vista puede ser referenciado por múltiples vistas. No tiene conocimiento del código específico de UI como la relación padre / hijo, posición, diseño, tamaño, etc. Por lo tanto, es mejor abrir la ventana secundaria en el código subyacente de la vista con el evento de cambio de estado de ViewModel o eventos de comando y argumentos de evento. De esta forma, puede especificar cuál es la vista primaria en la capa UI.