2009-09-13 12 views
5

Comment fermer une vue depuis son ViewModel?Prism2/MVVM Close View from ViewModel

J'ai une fenêtre WPF qui a défini plusieurs régions et qui est utilisée comme Shell pour héberger des vues pour mon application. Je voudrais avoir une vue capable de se retirer de la région, ou le fermer à partir d'un conteneur à onglets. Comment puis-je accomplir ce comportement à partir de ViewModel.

+0

précieux commentaires des membres, i ont pu coder avec succès. exemple de classe de mise en œuvre est publié en réponse à cette question. – Raj

Répondre

5

Cela dépend vraiment de l'architecture de votre application, mais voici comment je le fais avec Prism. D'abord, je veux dire, c'est ok pour que votre VM référence la vue aussi longtemps que ce n'est pas une implémentation concrète de la vue, c'est-à-dire des références par interface.

Je marie View et ViewModel en utilisant l'injection de dépendance, très similaire à la façon dont cela se fait dans le StockTraderRI. J'ai donc un IView et un IViewModel. IViewModel a une propriété appelée "Vue" de type IView.

A partir de la couche de code (pour moi, habituellement le contrôleur ... voir StockTraderRI) qui fonctionne avec vos régions, ajoutez le mécanisme pour retirer votre point de vue de la région.

Par exemple:

myRegion.Remove(myIViewModel.View); 

Si les régions sont gérées par un contrôleur, vous voudrez peut-être mettre un événement simple sur la machine virtuelle pour avertir quand une machine virtuelle veut être « fermée ». Vous pouvez également tester IEventAggregator si vous souhaitez utiliser un modèle de gestion des événements faible. Si la région est gérée dans la machine virtuelle, ajoutez simplement ce code là.

+0

Merci. Je pense que j'ai la logique. Mais je suis coincé où je résous l'interface du contrôleur du module. J'obtiens une exception de dépassement de pile. Contrôleur LoginController = this.container.Resolve (); renvoie une erreur Aucune suggestion? – Raj

+0

Il semble que votre conteneur d'unité ait des dépendances circulaires et/ou soit mal configuré. Je suivrais tous les constructeurs et m'assurerais que chaque paramètre injecté semble correct. Si vous pouvez essayer de coller le code d'installation du conteneur et peut-être quelques constructeurs de classes. –

+0

Salut pls vérifier le code que j'ai collé comme réponse à cette question. Merci encore. – Raj

7

Depuis votre ViewModel ne (et ne devrait pas) avoir une référence à la View, vous ne pouvez pas le fermer directement. Cependant, ce que vous pouvez faire est d'ajouter un Event dans votre ViewModel pour indiquer qu'il veut être fermé.

Josh Smith a écrit an article montrant comment faire (à mi-chemin à travers l'article).

+1

Salut merci, j'ai déjà traversé ça. Mais l'article de Josh n'utilise pas CompositeWPF, donc je me demande comment je pourrais mettre en œuvre un tel gestionnaire d'événements couplé avec Regions et Bootstrapper of Composite WPF. – Raj

+1

Vous prendriez ce code et au lieu de window.Close() en tant que votre gestionnaire, vous utiliseriez regionMananger.Regions ["MyRegion"]. Remove (fenêtre) –

+0

Bon article, d'ailleurs. –

3

Ce que mon module de connexion ressemble:

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 
} 

C'est le contrôleur:

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 
} 

Et ceci est mon ViewModel:

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 
}