2013-08-26 17 views
5

Mam AddClientViewModel, do którego odwołują się 2 widoki (AddClientView i SuggestedAddressesView). AddClientView jest formularzem, który ma pole dla adresu. Formularz ma przycisk sprawdzania poprawności, który zatwierdza wprowadzony adres za pomocą funkcji Geokodowanie. Jeśli zostanie zwrócony więcej niż jeden adres, zostanie wyświetlony przycisk SuggestedAddressesView.Otwarty/zamknięty widok z ViewModel

Oto jak jestem obecnie robi to:

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(); 
     } 
    } 

Oto konstruktor SuggestedAddressesView gdzie AddClientViewModel dziedziczy ViewModelBase

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

Inny problem mam jest kiedy wołam OnClosingRequest() z AddClientViewModel ... zarówno AddClientView i SuggestedAddressesView zamyka. Wiem, że tak się dzieje, ponieważ oba widoki odwołują się do tego samego ViewModel. To nie jest zachowanie, którego pragnę. Chciałbym móc samodzielnie zamknąć okno.

Czy otwierasz widok z właściwej struktury ViewModel MVVM i jak mogę uzyskać możliwość niezależnego zamykania okien?

Odpowiedz

5

Jak najszybciej odnieść się do elementów interfejsu użytkownika (w tym przypadku widoku) z VM, idziesz przed proponowanych wytycznych MVVM. Po prostu możemy wiedzieć, że tworzenie obiektu Window w VM jest nieprawidłowe.

Więc teraz na uzupełnianiu to:

  • Po pierwsze staraj się 1 View < -> 1 VM w aplikacji. Jest bardziej przejrzysty i pozwala na łatwe przełączanie między widokami Implementacje z tą samą logiką. Dodanie wielu widoków do tej samej maszyny wirtualnej, nawet jeśli nie jest "przełomowa", powoduje, że jest ona niezgrabna.
  • Teraz masz AddClientView i SuggestedAddressesView z własną maszyną wirtualną. Wspaniały!

Wdrażanie View Open/Close z VM:

  • Ponieważ nie możemy wejść do widoku bezpośrednio z naszej VM (zgodnie ze standardami), możemy użyć metod, takich jak używanie Messenger (MVVM Light), EventAggregator (PRISM) i tak dalej, aby wysłać "komunikat" z VM do widoku, gdy trzeba otworzyć/zamknąć widok i wykonać rzeczywistą operację w widoku.
  • W ten sposób maszyna wirtualna właśnie inicjuje komunikat i może być poddana testowi jednostkowemu "fine" dla tej samej operacji i nie odwołuje się do żadnych elementów interfejsu użytkownika.

Stosując podejście "Messenger", aby obsłużyć View otwarty:

  • Według logiki, jest to AddClientViewModel który musiałby poprosić o SuggestedAddressesView być otwarte.
  • W ten sposób po wykryciu SuggestedAddresses.Count > 0, wyślesz wiadomość do AddClientView z prośbą o otwarcie SuggestedAddressesView.
  • Po otrzymaniu tej wiadomości w AddClientView.xaml.cs zrobiłbyś to, co aktualnie robisz w VM. Utwórz obiekt o numerze SuggestedAddressesView i zadzwoń pod numer .Show().
  • Dodatkowym krokiem, który można dodać w powyższym kroku, jest przypisanie DataContext z SuggestedAddressesView jako SuggestedAddressesViewModel.

To wszystko. Teraz to, co mamy, kiedy jest wyświetlane, pokazuje komunikat, a widok z kolei tworzy i pokazuje SuggestedAddressesView. W ten sposób maszyna wirtualna nie odwołuje się do żadnego widoku i zachowujemy standardy MVVM.

Stosując podejście "Messenger", aby obsłużyć View bliską:

  • zamykania View jest dość prosta. Ponownie, gdy musisz zamknąć widok z VM, wysyłasz wiadomość do jej własnego widoku, prosząc o jej zamknięcie.
  • Po odebraniu tej wiadomości widok prawie sam się zamyka poprzez .Hide()/.Close() lub jakkolwiek chcesz się go pozbyć.

W tym przypadku każda maszyna wirtualna obsługuje zamknięcie własnego widoku i nie ma żadnych zależnych od siebie zależności.

Możesz użyć this jako punktu początkowego, aby poprowadzić cię w obsłudze "komunikatów" dla tego podejścia. ma dołączone pobieranie, które możesz pobrać i zobaczyć, jak działa Messenger. Dzieje się tak w przypadku MVVM Light, jeśli go nie używasz lub używasz czegoś innego/własnej implementacji MVVM, użyj go jako przewodnika, który pomoże ci uzyskać to, czego potrzebujesz.

+0

W porządku, to ma sens! Problem polega na tym, że chciałbym, aby informacje zebrane z ** SuggestedAddressesView ** były przekazywane do ** AddClientViewModel ** (stąd dlaczego używałem 1 VM dla 2 widoków). Powodem, dla którego to robię jest to, że adres wybrany w ** SuggestedAddressesView ** jest przypisany do klienta zdefiniowanego w ** AddClientViewModel **. – francisg3

+1

@ francisg3 spójrz na przykładowy link, który zamieściłem. Jeśli dostaniesz tam przykład, Drugie 'Okno' otwiera Modal/Non-Modal przekazuje informacje z powrotem do MainWindow. Jest to proces, którego używałbyś również do swoich wymagań. W zasadzie używałbyś Messengera do wysyłania wiadomości (tutaj wiadomość będzie danymi, które chcesz przesłać z SuggestedAddressViewModel do AddClientViewModel) – Viv

0

można użyć RelayCommand tak że wyślesz parametr w następujący sposób:

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

Za pomocą tego można zamknąć poszczególne widoki.

Przykład:

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

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

Aby otworzyć okno z ViewModel:

Tworzenie klasy NavigationService.cs dla okna otwierania: Niech NavigationService.cs

Teraz umieścić następujący kod w tym pliku klasy.

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

następnie. Utwórz instancję klasy NavigationService.cs plik MainWindowViewModel. Następnie

Window1ViewModel window1ViewModel = new Vindow1ViewModel(); 
window1ViewModel.Name = MainWindowTextValue; 
NavigationService navigationService = new NavigationService(); 
navigationService.ShowWindow1Screen(window1ViewModel); 
Powiązane problemy