2013-08-26 22 views
5

Ho un AddClientViewModel a cui fa riferimento 2 visualizzazioni (AddClientView e SuggestedAddressesView). AddClientView è un modulo con un campo per un indirizzo. Il modulo ha un pulsante di convalida che convalida l'indirizzo inserito utilizzando Geocoding. Se viene restituito più di un indirizzo, si apre SuggestedAddressesView.Apri/Chiudi vista da ViewModel

Ecco come Attualmente sto facendo:

AddClientViewModel:

private void ValidateExecute(object obj) 
    { 
     SuggestedAddresses = new ObservableCollection<DBHelper.GeocodeService.GeocodeResult>(GeoCodeTest.SuggestedAddress(FormattedAddress)); 

     .... 

     if (SuggestedAddresses.Count > 0) 
     { 
      var window = new SuggestedAddressesView(this); 
      window.DataContext = this; 
      window.Show(); 
     } 
    } 

Ecco il costruttore SuggestedAddressesView dove AddClientViewModel eredita da ViewModelBase

public SuggestedAddressesView(ViewModelBase viewModel) 
    { 
     InitializeComponent(); 
     viewModel.ClosingRequest += (sender, e) => this.Close(); 
    } 

L'altro problema che sto avendo è quando chiamo OnClosingRequest() da AddClientViewModel ... si chiude sia AddClientView che SuggestedAddressesView. So che questo accade perché entrambe le viste fanno riferimento allo stesso ViewModel. Questo non è il comportamento che voglio. Mi piacerebbe essere in grado di chiudere indipendentemente una finestra.

Sta aprendo una vista dalla struttura MVVM corretta di ViewModel e come potrei fare per poter chiudere le finestre in modo indipendente?

risposta

5

Non appena si fa riferimento a elementi dell'interfaccia utente (in questo caso la vista) dalla VM, si sta andando contro Linee guida MVVM suggerite. Con solo quello possiamo sapere che la creazione dell'oggetto Window nella VM è errata.

Così ora su rettificare questo:

  • In primo luogo cercare di mantenere un 1 Visualizza < -> 1 VM nell'applicazione. È più pulito e ti consente di cambiare le implementazioni della vista con la stessa logica molto facilmente. L'aggiunta di più viste alla stessa VM, anche se non "innovativa", la rende semplicemente goffa.
  • Quindi ora hai AddClientView e SuggestedAddressesView con la loro VM. Grande!

L'implementazione di un View Open/Close dal VM:

  • Dal momento che non siamo in grado di accedere alla visualizzazione direttamente dal nostro VM (per conformarsi alle norme), siamo in grado di utilizzare approcci come l'utilizzo di un Messenger (MVVM Luce), EventAggregator (PRISM) e così via per inviare un "messaggio" dalla VM alla vista quando è necessario aprire/chiudere una vista ed eseguire l'operazione effettiva nella vista.
  • In questo modo la VM inizia il messaggio e può essere testato unitamente per la stessa operazione e non fa riferimento a nessun elemento dell'interfaccia utente.

Utilizzando un approccio "Messenger" per gestire Visualizza aperta:

  • Secondo la vostra logica, è il AddClientViewModel che avrebbe dovuto chiedere il SuggestedAddressesView da aprire.
  • Pertanto, quando si rileva SuggestedAddresses.Count > 0, si invia un messaggio allo AddClientView che chiede di aprire lo SuggestedAddressesView.
  • In AddClientView.xaml.cs dopo aver ricevuto questo messaggio, si farebbe ciò che si sta facendo attualmente nella VM. Creare un oggetto di SuggestedAddressesView e chiamare .Show() su di esso.
  • Un ulteriore passaggio da aggiungere nel processo sopra descritto consiste nell'assegnare il numero DataContext di SuggestedAddressesView come SuggestedAddressesViewModel.

Questo è tutto. Ora quello che hai è, quando AddClientViewModel vuole SuggestedAddressesView mostrato, invia un messaggio alla propria vista e la vista a sua volta crea e mostra lo SuggestedAddressesView. In questo modo la VM non fa riferimento a nessuna vista e continuiamo a mantenere gli standard MVVM.

Utilizzando un approccio "Messenger" per gestire Visualizza vicino:

  • chiusura di un View è piuttosto semplice. Di nuovo quando è necessario chiudere la vista dalla VM, si invia un messaggio alla propria vista chiedendo che venga chiusa.
  • Alla ricezione di questo messaggio, la vista si chiude praticamente da solo tramite .Hide()/.Close() o comunque si vuole liberarsene.

In questo ogni VM gestisce la propria chiusura della vista e non si hanno dipendenze interconnesse.

È possibile utilizzare this come punto di partenza per guidare l'utente nella gestione dei "messaggi" per questo approccio. ha un download allegato che puoi ottenere e vedere come funziona lo Messenger. Questo è con MVVM Light, se non lo usi o usi qualcos'altro/la tua implementazione MVVM, usala come guida per ottenere quello che ti serve.

+0

OK, questo ha senso! Il problema che sto avendo è che mi piacerebbe che le informazioni raccolte da ** SuggestedAddressesView ** passassero al ** AddClientViewModel ** (quindi perché stavo usando 1 VM per 2 Visualizzazioni). Il motivo per cui lo sto facendo è che l'indirizzo selezionato in ** SuggestedAddressesView ** è assegnato a un client definito in ** AddClientViewModel **. – francisg3

+1

@ francisg3 guarda il link di esempio che ho pubblicato. Se si ottiene l'esempio, il secondo 'Window' ha aperto Modal/Non-Modal trasferisce le informazioni alla MainWindow. Questo è il processo che useresti anche per il tuo requisito. Ti piacerebbe usare Messenger per inviare un messaggio (qui il messaggio saranno i dati che vuoi inviare da SuggestedAddressViewModel a AddClientViewModel) – Viv

0

è possibile utilizzare RelayCommand in modo che si invia il parametro nel modo seguente:

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}" 

Usando questo è possibile chiudere le singole viste.

Esempio:

public ICommand CloseCommand 
    { 
     get 
     { 
      return new RelayCommand(OnClose, IsEnable); 
     } 
    } 

public void OnClose(object param) 
    { 
     AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView; 
     obj.Close(); 
    } 
0

per aprire la finestra dal ViewModel:

Crea classe NavigationService.cs per la finestra di apertura: Let NavigationService.cs

Ora mettete seguente codice in quel file di classe.

public void ShowWindow1Screen(Window1ViewModel window1ViewModel) 
     { 
      Window1= new Window1(); 
      Window1.DataContext = window1ViewModel; 
      Window1.Owner = Window1View; 
      Window1.ShowDialog(); 
     } 

quindi. Creare un'istanza del file MainWindowViewModel della classe NavigationService.cs. Quindi

Window1ViewModel window1ViewModel = new Vindow1ViewModel(); 
window1ViewModel.Name = MainWindowTextValue; 
NavigationService navigationService = new NavigationService(); 
navigationService.ShowWindow1Screen(window1ViewModel); 
Problemi correlati