Это было всего лишь 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 .
Спасибо Лорану и Маттео за то, что они мои первопроходцы ?