2009-09-13 21 views
5

¿Cómo cierro una vista desde su ViewModel?Prism2/MVVM Cerrar Vista desde ViewModel

Tengo una ventana WPF que ha definido varias regiones y se usa como un Shell para alojar vistas para mi aplicación. Me gustaría tener una Vista capaz de eliminarse de la Región, o cerrarla desde un contenedor con pestañas. ¿Cómo puedo lograr este comportamiento desde ViewModel?

+0

con valiosos comentarios de los miembros, i fueron capaces de codificar esto con éxito. muestra de clase de implementación se publica como una respuesta a esta pregunta. – Raj

Respuesta

5

Esto realmente depende de la arquitectura de su aplicación, pero así es como lo hago con Prism.

Primero quiero decir que es ok para que su referencia VM sea la vista siempre y cuando no se trate de una implementación concreta de la Vista, es decir, referencias por interfaz.

Me case la View y ViewModel usando la inyección de dependencia, muy similar a como se hace en StockTraderRI. Así que tengo un IView y un IViewModel. IViewModel tiene una propiedad llamada "Vista" de tipo IView.

Desde la capa de código (para mí, generalmente el controlador ... ver StockTraderRI) que funciona con sus regiones, agregue el mecanismo para eliminar su vista de la región.

Por ejemplo:

myRegion.Remove(myIViewModel.View); 

Si las regiones son manejados por un controlador, es posible que desee poner un evento simple en la máquina virtual para notificar cuando una VM quiere ser "cerrada". También puede experimentar con IEventAggregator si desea utilizar un modelo de evento débil. Si la región se maneja en la VM, simplemente agregue ese código allí.

+0

Gracias. Creo que tengo la lógica. Pero estoy atascado donde resuelvo la interfaz del controlador desde el Módulo. Obtengo una excepción de desbordamiento de pila. Controlador LoginController = this.container.Resolve (); arroja un error. ¿Alguna sugerencia? – Raj

+0

Parece que su contenedor de unidad tiene algunas dependencias circulares y/o está configurado incorrectamente. Seguiría todos los constructores y me aseguraré de que cada parámetro inyectado se vea correcto. Si puede intentar pegar el código de configuración del contenedor y quizás algunos constructores de clases. –

+0

Hola, por favor revisa el código que he pegado como respuesta a esta pregunta. Gracias de nuevo. – Raj

7

Dado que su ViewModel no tiene (y no debe) tener una referencia al View, no puede cerrarlo directamente. Sin embargo, lo que puede hacer es agregar un Event en su ViewModel para indicar que quiere que se cierre.

Josh Smith ha escrito an article que muestra cómo hacerlo (aproximadamente a la mitad del artículo).

+1

Hola, gracias, ya he pasado por eso. Pero el artículo de Josh no usa CompositeWPF, así que me pregunto cómo podría implementar un controlador de eventos así junto con Regions y Bootstrapper of Composite WPF. – Raj

+1

Usted tomaría ese código y en lugar de window.Close() como su manejador, usará regionMananger.Regions ["MyRegion"]. Remove (window) –

+0

Buen artículo, por cierto. –

3

Esto cómo mi módulo de sesión se parece a:

public class LoginModule : IModule 
{ 
    private readonly IUnityContainer container; 

    public LoginModule(IUnityContainer container) 
    { 
     this.container = container; 
    } 

    #region IModule Members 

    public void Initialize() 
    { 
     this.container.RegisterType<ILoginController, LoginController>(new ContainerControlledLifetimeManager()); 
     this.container.RegisterType<ILoginView, LoginView>(); 
     this.container.RegisterType<ILoginViewModel, LoginViewModel>(); 

     ILoginController controller = this.container.Resolve<ILoginController>(); 
     controller.Run(); 
    } 

    #endregion 
} 

Este es el controlador:

public class LoginController : ILoginController 
{ 
    private readonly IRegionManager regionManager; 
    private readonly ILoginViewModel model; 

    public LoginController(IRegionManager regionManager, ILoginViewModel model) 
    { 
     this.regionManager = regionManager; 
     this.model = model; 
     model.RequestClose += new EventHandler(model_RequestClose); 
    } 

    void model_RequestClose(object sender, EventArgs e) 
    { 
     regionManager.Regions["LoginRegion"].Remove(model.View); 
    } 

    #region ILoginController Members 

    public void Run() 
    { 
     // Register views here 
     regionManager.Regions["LoginRegion"].Add(model.view); 
    } 

    #endregion 
} 

y este es mi modelo de vista:

public class LoginViewModel : ViewModelBase, ILoginViewModel 
{ 
    IEventAggregator _eventAggregator; 
    RelayCommand _loginCommand; 
    private readonly UserProfileRepository _userProfileRepository; 
    public event EventHandler RequestClose; 

    public ICommand LoginCommand 
    { 
     get 
     { 
      if (_loginCommand == null) 
      { 
       _loginCommand = new RelayCommand(
        param => this.Login(), 
        param => this.IsValid()); 
      } 
      return _loginCommand; 
     } 
    } 

    public LoginViewModel(IEventAggregator eventAggregator, UserProfileRepository userProfileRepository, ILoginView view) 
    { 
     this._eventAggregator = eventAggregator; 
     this._userProfileRepository = userProfileRepository; 
     this.View = view; 
    } 

    #region ILoginViewModel Members 

    public ILoginView View { get; private set; } 

    #endregion 
} 
Cuestiones relacionadas