2010-10-04 10 views
12

ja przycisku w widoku, związany z właściwości ICommand od ViewModel (w rzeczywistości jest to RelayCommand z mvvv-light)Skąd bierze się logika nawigacji, View, ViewModel lub gdziekolwiek indziej?

Jeżeli użytkownik kliknie na przycisk chcę, aby przejść do nowego widoku. Oczywiście usługa NavigationService jest częścią View a ViewModel. Oznacza to, że nawigacja jest odpowiedzialna za widok? Ale w moim przypadku widok, który zrobię po kliknięciu przycisku, zależy od wielu czynników, w tym od tego, kto jest zalogowanym użytkownikiem, od stanu, w którym znajduje się baza danych itp. Z pewnością widok nie powinien wymagać wszystkich te informacje.

Jaka jest preferowana opcja wykonywania usługi NavigationService.Navigate call?

Odpowiedz

12

Jeśli korzystasz już z MVVM Light, jedną z opcji jest skorzystanie z dołączonej magistrali komunikatów. Wiążesz więc przycisk z RelayCommand w modelu widoku, jak już powiedziałeś, że już robisz. W programie obsługi RelayCommand możesz podjąć decyzję, do którego widoku nawigować. Zachowuje to całą logikę w modelu widoku.

Po tym, jak program obsługi zdecyduje, do którego widoku nawigować, może opublikować komunikat na magistrali komunikatów. Twój widok będzie nasłuchiwał tego komunikatu, a następnie użyje usługi NavigationService do wykonania nawigacji. Więc nie robi nic innego niż czekanie na polecenie nawigacji gdzieś, a następnie nawigację tam, gdzie jest to powiedziane.

Robiłem to, definiując klasę NavigationMessage, którą moje modele widoku mogą publikować, i widok klasy bazowej, której moje widoki dziedziczą, z której składa się słuchacz. NavigationMessage wygląda następująco:

public class NavigationMessage : NotificationMessage 
{ 
    public string PageName 
    { 
     get { return base.Notification; } 
    } 

    public Dictionary<string, string> QueryStringParams { get; private set; } 

    public NavigationMessage(string pageName) : base(pageName) { } 

    public NavigationMessage(string pageName, Dictionary<string, string> queryStringParams) : this(pageName) 
    { 
     QueryStringParams = queryStringParams; 
    } 
} 

Pozwala to po prostu przekazując nazwę strony, lub ewentualnie w tym również wszelkie niezbędne parametry ciągu zapytania. Procedura obsługi RelayCommand opublikuje tę wiadomość tak:

private void RelayCommandHandler() 
{ 
    //Logic for determining next view, then ... 
    Messenger.Default.Send(new NavigationMessage("ViewToNavigate")); 
} 

Wreszcie klasa widok baza wygląda tak:

public class BasePage : PhoneApplicationPage 
{ 
    public BasePage() 
    { 
     Messenger.Default.Register<NavigationMessage>(this, NavigateToPage); 
    } 

    protected void NavigateToPage(NavigationMessage message) 
    { 
     //GetQueryString isn't shown, but is simply a helper method for formatting the query string from the dictionary 
     string queryStringParams = message.QueryStringParams == null ? "" : GetQueryString(message); 

     string uri = string.Format("/Views/{0}.xaml{1}", message.PageName, queryStringParams); 
     NavigationService.Navigate(new Uri(uri, UriKind.Relative)); 
    } 
} 

to zakładając konwencję gdzie wszystkie poglądy są w folderze „Widoki” w katalogu głównym aplikacji. Działa to dobrze dla naszej aplikacji, ale oczywiście można ją rozszerzyć, aby obsługiwać różne scenariusze organizowania swoich poglądów.

+0

Doskonała sugestia, dzięki! –

+0

Przyznam, że nie jestem zbyt zaznajomiony z systemem Messenger, który oferuje MVVM-Light. Czy w związku z dalszą refleksją nie oznacza to, że wszystkie widoki zarejestrują się i usłyszą ten komunikat NavigationMessage? –

+0

Przypuszczam, że to może być problem. Używam tej techniki w kontekście aplikacji Windows Phone 7, w której mam tylko jeden aktywny widok na raz, więc działa to doskonale. Jeśli pracujesz w wersji Silverlight lub WPF dla komputerów stacjonarnych i masz jednocześnie wiele aktywnych widoków, widzę, gdzie może to być problem. Będę musiał pomyśleć o tym więcej. –

6

Ostrzeżenie: opinionated alert MVVM początkujących :) (jestem bardzo nowy w MVVM, ale cieszyłem się dużo tej pory.)

Dobre pytanie. Odkryłem, że jest to całkowicie wykonalne (jeśli trochę brzydkie w niektórych miejscach), aby wyśmiać NavigationService i przekazać INavigationService do ViewModel. W rzeczywistości można nawet uczynić interfejs nieco ładniejszym w przypadku generycznych, aby przekazać w postaci typ (jako argument typu) zamiast identyfikatora URI ciągu.

Jednak odkryłem, że trochę się rozluźniłem, gdy chodzi o dodatkowe dane związane z nawigacją ... Nie znalazłem dobrego miejsca do zrobienia całego kodowania/odkodowania w celu propagacji Stan dobry. Podejrzewam, że ViewModelFactory może być częścią tego równania ...

Tak więc, nie jest to idealne rozwiązanie - ale przynajmniej ViewModel może być odpowiedzialny za akcję "Nawiguj teraz" (lub "wróć").

+0

Ja również cieszę się z MVVM, ale wydaje mi się, że niektóre szablony Silverlight nie są szczególnie przyjazne dla MVVM; nawigacja jest jedna.Dzięki za pomysł przekazania typu, a nie ciąg jako "uri". ma to sens w tym kontekście. –

Powiązane problemy