2010-10-04 1 views
12

я кнопка в представлении, связанный со свойством ICommand в ViewModel (на самом деле это RelayCommand от mvvv света)Где находится логика навигации, View, ViewModel или в другом месте?

Если пользователь нажимает на кнопку, я хочу, чтобы перейти к новому взгляду. Конечно, NavigationService является частью View, а не ViewModel. Это означает, что навигация несет ответственность за просмотр? Но в моем случае представление, которое будет отображаться при нажатии кнопки, зависит от множества факторов, в том числе от того, кем является зарегистрированный пользователь, состояния, в котором находится база данных и т. Д. Конечно, View не должен нуждаться во всех эта информация.

Что является предпочтительным вариантом для выполнения вызова NavigationService.Navigate?

ответ

12

Если вы уже используете MVVM Light, один из вариантов заключается в использовании шины сообщений, которую он включает. Таким образом, вы привязываете свою кнопку к RelayCommand на модели представления, как вы уже сказали, что уже делаете. В обработчике вашего RelayCommand вы можете принять решение о том, на какой взгляд перейти. Это сохраняет всю эту логику в модели представления.

После того, как ваш обработчик задал, к какому виду перейти, он может опубликовать сообщение на шине сообщений. Ваше представление будет прослушивать это сообщение, а затем использовать NavigationService для фактического выполнения навигации. Таким образом, это ничего не значит, кроме как ждать, когда ему скажут, что нужно куда-то перемещаться, а затем переходить туда, где сказано.

Я делал это, определяя класс NavigationMessage, который могут публиковать мои модели просмотра, и базовый класс представления, которые наследуют мои представления, из которых содержит слушателя. NavigationMessage выглядит следующим образом:

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

Это позволяет просто передавая имя страницы, или, возможно, также включая все необходимые строки запроса параметров. Обработчик RelayCommand бы опубликовать это сообщение так:

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

Наконец, вид базового класса выглядит следующим образом:

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

Это предполагает, что конвенции, где все виды находятся в папке «Views» в корне приложения. Это отлично подходит для нашего приложения, но, конечно, это может быть расширено для поддержки различных сценариев для того, как вы упорядочиваете свои представления.

+0

Отличное предложение, спасибо! –

+0

Я признаю, что я не слишком хорошо знаком с системой Messenger, которую предлагает MVVM-Light. Что касается дальнейшего размышления, значит ли это, что все взгляды будут регистрироваться и слышать этот NavigationMessage? –

+0

Я полагаю, это может быть проблемой. Я использую эту технику в контексте приложения Windows Phone 7, где у меня есть только один вид активности за один раз, поэтому он работает отлично. Если вы работаете в настольной версии Silverlight или WPF, и у вас одновременно есть несколько представлений, я вижу, где это может быть проблемой. Подумайте об этом еще немного. –

6

Предупреждение: самоуверенный MVVM новичку предупреждение :) (я новичок в MVVM, но наслаждаться этим много до сих пор.)

Хороший вопрос. Я обнаружил, что это вполне осуществимо (если немного уродливое место), чтобы высмеять NavigationService и передать INavigationService в ViewModel. На самом деле, вы даже можете сделать интерфейс немного приятнее с generics, передать в тип (как аргумент типа), а не URI строки.

Тем не менее, я обнаружил, что я немного отклеился, когда речь заходит о том, куда вы добавляете дополнительные данные, связанные с навигацией ... Я не нашел подходящего места для того, чтобы все кодирование/кодирование не распространялось аккуратно. Я подозреваю, что ViewModelFactory вполне может быть частью этого уравнения ...

Итак, это не идеальное решение, но, по крайней мере, ViewModel может нести ответственность за действие «navigate now» (или «вернуться»).

+0

Я тоже наслаждаюсь MVVM, howerver, похоже, есть некоторые бит шаблонов Silverlight, которые не являются особенно дружественными MVVM; навигация один.Спасибо за идею передачи типа, а не строки, как «uri». что имеет смысл в этом контексте. –

Смежные вопросы