Exrin — это фреймворк MVVM с более высокими уровнями абстракции, чем большинство других фреймворков. Он предназначен для работы с Xamarin Forms, но не имеет зависимости от них. Он, безусловно, подкидывает мысли о том, как следует разрабатывать проект, и при этом предоставляет некоторые очень продвинутые функции навигации, которыми можно пользоваться с относительной легкостью.
Exrin основан на ViewModel-навигации. Это означает, что переход осуществляется от ViewModel к ViewModel, а не от View к View. Каждый View связан с ViewModel по принципу 1 к 1, но ViewModel никогда не распознаёт того, что View является связанным с ним. На следующей диаграмме представлен обзор того, как составляющие Exrin сочетаются друг с другом по отношению к навигации. Все это будет объяснено ниже.
Пример кода: Вашему вниманию предлагается небольшой шаблон проекта Exrin Sample, который даст Вам представление о том, как на деле работает мобильное приложение, созданное с использованием данной технологии.
Стеки
У Xamarin Forms есть NavigationStack и ModalStack. Exrin никогда не использует ModalStack, только NavigationStack. Exrin создает собственные стеки. Всякий раз, когда Вам нужно переключать стеки, он меняет MainPage на следующий стек и также позволяет вернуться к предыдущему стеку, прямо туда, где Вы остановились.
Обычный вариант, который я использую в этом случае — это AuthenticationStack и MainStack. Вам вряд ли нужно то, чтобы пользователь с помощью обратной навигации мог опять оказаться на странице входа в систему. Она является часть другой передачи страниц и должна храниться отдельно. Стеки на самом деле создаются очень просто: Вы устанавливаете стартовую страницу и назначаете Views для ViewModels.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Authentication is just an enum used to keep a track of the views. This is the ViewKey. protected override void Map() { base.NavigationMap<LoginView, LoginViewModel>(nameof(Authentication.Login)); } public override string NavigationStartKey { get { return nameof(Authentication.Login); } } |
NoHistory и кэширование View
Перед тем как двигаться дальше, я бы хотел обратить Ваше внимание на небольшую особенность, которая позволяет кэшировать view, благодаря чему ему не приходится воссоздаваться всякий раз, когда Вы визуализируйте его. NoHistory является интересной функцией, поскольку с помощью неё Вы можете обозначать любое View-ViewModel путём отображения. Когда эти значения установлены верно, тогда в случае, если одно view проталкивается поверх другого или если изменяется стек, то это view будут без разговоров снято со стека. И при возвращении, его больше не будет в истории навигации.
1 | base.NavigationMap<SplashView, SplashViewModel>(nameof(Authentication.Splash), new MapOptions() { NoHistory = true }); |
Переопределение ViewModel
Одним из больших преимуществ Exrin является то количество переопределений, которое вы получаете в каждом ViewModel для начала или завершения задач на любом этапе процесса навигации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // This View is about to be navigated to. Do anything before the View is pushed to the stack and made visible. // Will wait for this to return before the View is pushed to the stack. public override Task OnPreNavigate(object args) { } // When this View is displayed again because the page on top of it was popped from the stack public override Task OnBackNavigated(object args) { } // When the page has been navigated to public override Task OnNavigated(object args) { } // When the View this is mapped to is popped from the Navigation Stack. public override void OnPopped() { } // When the View this is mapped to has its OnAppearing event called public override void OnAppearing() { } // When the View this is mapped to has the disappearing event called public override void OnDisappearing() { } // When the hardware back button is pressed public override bool OnBackButtonPressed() { } |
Навигация
Навигация в Exrin фактически осуществляется с помощью метода операции разделения (Operation Separation). Вы просто возвращаете результат от Operation во ViewModel, и Exrin делает все остальное. В примере ниже показывается результат навигации. На этом стеке состоится переход к Main Stack и Main View. Главное в этом стеке — имя View.
1 | new Result() { ResultAction = ResultType.Navigation, Arguments = new NavigationArgs() { Key = Main.Main, StackType = Stack.Main } }; |
Вы можете свободно взаимодействовать с NavigationService напрямую путем ввода INavigationService. NavigationService имеет следующее определение.
1 2 3 4 5 6 7 8 9 | Task Navigate(string key); Task Navigate(string key, object args); Task Navigate(object stackIdentifier, string key, object args); Task Navigate(string key, object args, IStackOptions options); StackResult Navigate(IStackOptions options); |
Ключом будет то, что Вы припишите к View в стеке. StackIdentifier — это ключ, который Вы назначили в стеке. Если вы не предоставите StackIdentifier, то будет считаться, что Вы имеете в виду тот же самый стек. Args — это объект, который содержит все, что Вам понадобится передавать к ViewModel.
Exrin заботится о переключении стека и выталкивании или проталкивании views для достижения цели, Вам необязательно знать о том, как добраться до страницы и стека, нужно просто внести запланированную цель.
IStackOptions предназначен для переключения стеков и навигации к странице, но, кроме того, он обеспечивает большую гибкость в том, как его можно использовать. Например, если Вам нужно переключиться на стек, и Вы не знаете в то время, какое View запущено, но Вы не хотите при этом его изменять, то Вы можете просто отправить его через StackChoice, который на самом деле StackIdentifier (приношу свои извинения за несогласованность наименований, я мог бы сформировать критическое изменение по ходу дела).
У Вас также есть возможность загрузить стек с определённым числом предварительно загруженных views. Если вы хотите перейти к view в стеке, но для этого предварительно нужно загрузить несколько views, тогда Вы можете использовать PreDefinedStack, чтобы определить их. Они будут загружены в стек раньше, чем ViewKey. Это происходит в фоновом режиме, так что пользователь не увидит мерцающих страниц.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public interface IStackOptions { object StackChoice { get; } string ViewKey { get; set; } object Args { get; } /// <summary> /// An ordered array with the Page Keys for a stack to be preloaded.The last page on the array will be the visible one. /// </summary> IDictionary<string, object> PredefinedStack { get; } /// <summary> /// If the ArgsKey is blank pass the args through. Otherwise the ArgsKey must match the ViewKey being loaded for the args to be passed. /// </summary> string ArgsKey { get; } } |
Контейнер View
Последний концепт, который я собираюсь представить, — это View Hierarchy, разработанный специально для таких более сложных views, как MasterDetailPage и TabbedPage. Вы помещаете стек во ViewContainer. В случае с TabbedPages и MasterDetailPages Вы помещаете несколько стеков в контейнер.
В момент осуществления навигации Вы всё ещё выбираете, к какому стеку или странице совершить переход. Exrin обрабатывает все остальное и демонстрирует правильное view.
Эти views немного сложнее, но вы можете ознакомиться с моим Tesla Example, чтобы увидеть MasterDetailPage и TabbedPage в действии.
Автор: Adam Pedley
Источник: Статья в блоге автора
Написать ответ