Статьи

NavigationService для WinRT

Это было всего лишь 1,5 года назад, но, похоже, уже очень давно Лоран Бюньон описал «сервис просмотра» для навигации по Windows Phone , обычно известный как NavigationService . Я включил этот код в моей # wp7nl библиотеке на CodePlex  и использую его с удовольствием до сих пор (и много других людьми , которых я знаю , делали так хорошо), время идет, а пришел Windows 8 и WinRT и метро Стиль приложений.

Лоран также перенес свою среду MVVMLight на WinRT. Но NavigationService никогда не был основной частью MVVMLight (поэтому я поместил его в библиотеку # wp7nl), и портирование его на WinRT также оказалось немного трудным. Некоторые из его помещений, где больше не действительны — наиболее заметен способ получения основного фрейма приложения путем доступа к Application.Current.RootVisual, который не работает в WinRT. Я немного повозился с кодом, нигде не собирался и оставил его там. Поэтому я был рад, что увидел своего коллегу по разработке Windows Phone MVP Маттео ПаганиЧирикать он получил NavigationService для работы. Он был достаточно любезен, чтобы отправить мне код. Он в основном скопировал код из Windows Phone и сделал общедоступными приложения rootFrame, созданные в het App.xaml.cs. Опрятный трюк с единственным недостатком, который вы должны скопировать код для каждого приложения. По ходу дела, обычно легче увидеть чужую идею и улучшить ее, чем придумать ее на ровном месте. Я поиграл с ним и сумел избавиться от необходимости копировать код, чтобы я мог поместить его в библиотеку.

И вот она, улучшенная версия NavigationService для WinRT, основанная на коде Маттео, основанном на коде Лорана 😉

Прежде всего, интерфейс NavigationService:

using System;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public interface INavigationService
  {
    event NavigatingCancelEventHandler Navigating;
    void Navigate(Type type);
    void Navigate(Type type, object parameter);
    void Navigate(string type);
    void Navigate(string type, object parameter);
    void GoBack();
  }
}

Это выглядит как старый интерфейс, за некоторыми заметными исключениями. Прежде всего, метод NavigateTo переименовывается в Navigate, чтобы имитировать имя метода, используемого в самом WinRT. И это имеет не одну, а четыре перегрузки. Первые два довольно логичны — WinRT использует не URI для навигации, а фактический объект Type, что делает возможным строго типизированную навигацию. И это также поддерживает перегрузку для объекта параметра. Два других метода, с объектом строкового типа… хорошо посмотрите сами ниже, в реализации сервиса:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public class NavigationService : INavigationService
  {
  public NavigationService(Frame mainFrame)
  {
    _mainFrame = mainFrame;
  }

  private Frame _mainFrame;
  
  public event NavigatingCancelEventHandler Navigating;

  public void Navigate(Type type)
  {
    _mainFrame.Navigate(type);
  }

  public void Navigate(Type type, object parameter)
  {
    _mainFrame.Navigate(type, parameter);
  }

  public void Navigate(string type, object parameter)
  {
    _mainFrame.Navigate(Type.GetType(type), parameter);
  }

  public void Navigate(string type)
  {
    _mainFrame.Navigate(Type.GetType(type));
  }

  public void GoBack()
  {
    if (_mainFrame.CanGoBack)
    {
      _mainFrame.GoBack();
    }
  }  
}

Таким образом, методы строкового типа позволяют указать страницу для навигации по строке. Прежде чем вы все подумали, что на этот раз я действительно потерял свои шарики, заново представив слабонабираемую навигацию, как в то время, когда команда Windows представила строго типизированный: я специально добавил это, чтобы позволить инициировать навигацию из ViewModel, содержащейся в сборке, не содержащей код XAML , Это также позволяет вам тестировать код. Именно так я построил свои решения для Windows Phone, и я собираюсь пойти по этому пути в Windows 8. 😉

В любом случае, в этом коде чего-то не хватает: EnsureMainFrame, который просматривал корневую страницу, для которой Matteo использовал открытое свойство. Я полностью удалил его и добавил конструктор, принимающий эту корневую страницу. Создав этот конструктор, я удалил конструктор по умолчанию, поэтому зарегистрировал NavigationService в контейнере SimpleIoc, поставляемом с MVVMLight, в файле App.xaml.cs, например так:

SimpleIoc.Default.Register<INavigationService, Wp7nl.Utilities.NavigationService>();

как мы сделали в коде Windows Phone, больше не будет работать. К счастью, SimpleIoc также поддерживает фабричные методы для создания экземпляра. Итак, теперь вы идете в App.xaml.cs вашего приложения для Windows 8, находите метод OnLaunched и сразу за этой строкой:

var rootFrame = new Frame();

Вы добавляете этот кусок кода:

SimpleIoc.Default.Register<INavigationService>(() => 
                                   {return new NavigationService(rootFrame);});

 Теперь, если ваш код XAML и ViewModel находятся в одной сборке, вы можете вызвать NavigationService, чтобы перейти на главную страницу:

SimpleIoc.Default.GetInstance<INavigationService>().Navigate(typeof(MainPage));

 или если вы немного упрямы, как я, и хотели бы разделить ViewModel и представления, вы можете использовать перегрузку строки, чтобы указать полное имя и, например, использовать его в команде ViewModel, подобной этой

public ICommand TestNavigatieCommand
{
   get
   {
     return new RelayCommand(() => 
       SimpleIoc.Default.GetInstance<INavigationService>().Navigate("MyApp.MainPage,MyApp"));
   }
}

И вот, у вас есть полнофункциональный NavigationService для Windows 8. Код можно скачать здесь . Я скоро включу его в временный порт библиотеки # wp7nl под названием win8nl .

Спасибо Лорану и Маттео за то, что они мои первопроходцы 😉