2009-09-13 15 views
5

Come si chiude una vista dal suo ViewModel?Prism2/MVVM Chiudi vista da ViewModel

Ho una finestra WPF che ha definito più regioni e viene utilizzata come shell per ospitare le visualizzazioni per la mia applicazione. Mi piacerebbe avere una vista in grado di rimuovere se stessa dalla regione, o chiuderla da un contenitore a schede. Come posso realizzare questo comportamento da ViewModel.

+0

con preziosi commenti dei membri, i sono stati in grado di codificare questo con successo. esempio di classe di implementazione è pubblicato come risposta a questa domanda. – Raj

risposta

5

Questo dipende molto dall'architettura dell'app, ma ecco come lo faccio con Prism.

Per prima cosa voglio dire, è ok avere la tua VM riferimento alla vista purché non sia un'implementazione concreta della vista, cioè dei riferimenti per interfaccia.

Ho sposato View e ViewModel utilizzando l'iniezione delle dipendenze, molto simile a come è fatto in StockTraderRI. Quindi ho un IView e un IViewModel. IViewModel ha un nome chiamato "View" di tipo IView.

Dal livello di codice (per me, di solito il controller ... vedi StockTraderRI) che funziona con le regioni, aggiungere il meccanismo per rimuovere la vista dalla regione.

Ad esempio:

myRegion.Remove(myIViewModel.View); 

Se le regioni sono gestite da un controller, si consiglia di mettere un semplice evento sul VM per notificare quando una VM vuole essere "chiuso". È anche possibile sperimentare con IEventAggregator se si desidera utilizzare un modello con evento debole. Se la regione viene gestita nella VM, è sufficiente aggiungere quel codice lì.

+0

Grazie. Penso di avere la logica. Ma sono bloccato dove risolvo l'interfaccia del controller dal modulo. Ottengo un'eccezione di overflow dello stack. LoginController controller = this.container.Resolve (); genera un errore Eventuali suggerimenti? – Raj

+0

Sembra che il tuo container di unità abbia alcune dipendenze circolari che si accendono e/o sono configurate in modo errato. Seguirò tutti i costruttori e mi assicurerò che ogni parametro iniettato sia corretto. Se riesci a provare ad incollare il codice di configurazione del contenitore e magari alcuni costruttori di classi. –

+0

Ciao pls controlla il codice che ho incollato come risposta a questa domanda. Grazie ancora. – Raj

7

Poiché il numero ViewModel non ha (e non dovrebbe) un riferimento allo View, non è possibile chiuderlo direttamente. Tuttavia, ciò che puoi fare è aggiungere unnel tuo ViewModel per indicare che vuole essere chiuso.

Josh Smith ha scritto an article mostrando come eseguire questa operazione (circa a metà dell'articolo).

+1

Ciao grazie, ne ho già parlato. Ma l'articolo di Josh non usa CompositeWPF, quindi mi chiedo come implementare un gestore di eventi simile a Regions e Bootstrapper di Composite WPF. – Raj

+1

Dovresti prendere quel codice e invece di window.Close() come gestore, dovresti usare regionMananger.Regions ["MyRegion"]. Rimuovi (finestra) –

+0

Un buon articolo, a proposito. –

3

questo come il mio modulo di login appare come:

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 
} 

Questo è il controller:

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 
} 

E questo è il mio 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 
} 
Problemi correlati