Navigace v podnikových aplikacích
Poznámka:
Tato elektronická kniha byla publikována na jaře roku 2017 a od té doby nebyla aktualizována. Existuje mnoho v knize, která zůstává cenná, ale některé materiály jsou zastaralé.
Xamarin.Forms zahrnuje podporu navigace na stránce, která obvykle vede k interakci uživatele s uživatelským rozhraním nebo samotnou aplikací v důsledku interních změn stavu řízeného logikou. Navigace ale může být složitá pro implementaci v aplikacích, které používají model model-View-ViewModel (MVVM), protože musí být splněny následující výzvy:
- Jak identifikovat zobrazení, na které se má přejít, pomocí přístupu, který nezavádí úzkou vazbu a závislosti mezi zobrazeními.
- Jak koordinovat proces, na který se má zobrazení přejít, vytvoří instanci a inicializuje se. Při použití MVVM se model zobrazení a zobrazení musí vytvořit instanci a přidružit k sobě prostřednictvím kontextu vazby zobrazení. Když aplikace používá kontejner injektáž závislostí, vytvoření instance zobrazení a modelů zobrazení může vyžadovat konkrétní stavební mechanismus.
- Určuje, jestli se má provést navigace typu první zobrazení, nebo zobrazit navigaci typu model-first. Při první navigaci zobrazení se stránka, na které chcete přejít, odkazuje na název typu zobrazení. Během navigace se vytvoří instance zadaného zobrazení spolu s odpovídajícím modelem zobrazení a dalšími závislými službami. Alternativním přístupem je použít navigaci typu model-first, kde stránka, na které chcete přejít, odkazuje na název typu modelu zobrazení.
- Jak vyčistit navigační chování aplikace napříč zobrazeními a modely zobrazení. Model MVVM poskytuje oddělení mezi uživatelským rozhraním aplikace a jeho prezentací a obchodní logikou. Chování aplikace při navigaci ale často pokrývá části uživatelského rozhraní a prezentací aplikace. Uživatel bude často inicializovat navigaci ze zobrazení a zobrazení bude nahrazeno v důsledku navigace. Navigace ale může být často potřeba iniciovat nebo koordinovat také z modelu zobrazení.
- Jak předat parametry během navigace pro inicializační účely. Pokud například uživatel přejde do zobrazení pro aktualizaci podrobností objednávky, budou se data objednávky muset předat do zobrazení, aby mohla zobrazit správná data.
- Jak koordinovat navigaci, aby byla zajištěna dodržování určitých obchodních pravidel. Uživatelům se například může zobrazit výzva před přechodem z zobrazení, aby mohli opravit všechna neplatná data nebo být vyzváni k odeslání nebo zahození jakýchkoli změn dat provedených v zobrazení.
Tato kapitola řeší tyto výzvy tím, že prezentuje NavigationService
třídu, která se používá k zobrazení navigace na první stránce modelu.
Poznámka:
Aplikace NavigationService
je určena pouze k provádění hierarchické navigace mezi instancemi ContentPage. Použití služby k navigaci mezi jinými typy stránek může vést k neočekávanému chování.
Navigace mezi stránkami
Navigační logika se může nacházet v kódu zobrazení nebo v modelu vázaného zobrazení dat. I když umístění navigační logiky do zobrazení může být nejjednodušším přístupem, není snadné ji testovat pomocí testů jednotek. Umístění navigační logiky do tříd modelu zobrazení znamená, že logiku je možné provádět pomocí testů jednotek. Model zobrazení pak může implementovat logiku pro řízení navigace, aby se zajistilo, že se vynucují určitá obchodní pravidla. Aplikace například nemusí uživateli povolit navigaci mimo stránku, aniž by nejprve zajistila platnost zadaných dat.
Třída NavigationService
je obvykle vyvolána z modelů zobrazení za účelem zvýšení testovatelnosti. Přechod na zobrazení z modelů zobrazení ale vyžaduje, aby modely zobrazení odkazovaly na zobrazení, a zejména zobrazení, ke kterým není přidružený aktivní model zobrazení, což se nedoporučuje. Proto uvedený typ NavigationService
modelu zobrazení určuje jako cíl, na který se má přejít.
Mobilní aplikace eShopOnContainers používá NavigationService
třídu k poskytnutí první navigace modelu. Tato třída implementuje INavigationService
rozhraní, které je znázorněno v následujícím příkladu kódu:
public interface INavigationService
{
ViewModelBase PreviousPageViewModel { get; }
Task InitializeAsync();
Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase;
Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase;
Task RemoveLastFromBackStackAsync();
Task RemoveBackStackAsync();
}
Toto rozhraní určuje, že implementovat třídu musí poskytovat následující metody:
Způsob | Účel |
---|---|
InitializeAsync |
Při spuštění aplikace provede navigaci na jednu ze dvou stránek. |
NavigateToAsync |
Provede hierarchickou navigaci na zadanou stránku. |
NavigateToAsync(parameter) |
Provede hierarchickou navigaci na zadanou stránku a předá parametr. |
RemoveLastFromBackStackAsync |
Odebere předchozí stránku z navigačního zásobníku. |
RemoveBackStackAsync |
Odebere všechny předchozí stránky z navigačního zásobníku. |
Kromě toho rozhraní určuje, INavigationService
že implementovat třídu musí poskytovat PreviousPageViewModel
vlastnost. Tato vlastnost vrátí typ modelu zobrazení přidružený k předchozí stránce v navigačním zásobníku.
Poznámka:
Rozhraní INavigationService
obvykle také určuje metodu GoBackAsync
, která se používá k programovému návratu na předchozí stránku v navigačním zásobníku. Tato metoda však v mobilní aplikaci eShopOnContainers chybí, protože není nutná.
Vytvoření instance navigationservice
Třída NavigationService
, která implementuje INavigationService
rozhraní, je registrována jako singleton s kontejnerem injektáže závislostí Autofac, jak je znázorněno v následujícím příkladu kódu:
builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
Rozhraní INavigationService
je vyřešeno v konstruktoru ViewModelBase
třídy, jak je znázorněno v následujícím příkladu kódu:
NavigationService = ViewModelLocator.Resolve<INavigationService>();
Vrátí odkaz na NavigationService
objekt uložený v kontejneru injektáže závislostí Autofac, který je vytvořen metodou InitNavigation
ve App
třídě. Další informace najdete v tématu Navigace při spuštění aplikace.
Třída ViewModelBase
ukládá NavigationService
instanci do NavigationService
vlastnosti typu INavigationService
. Proto všechny třídy modelu zobrazení, které jsou odvozeny z ViewModelBase
třídy, mohou použít NavigationService
vlastnost pro přístup k metodám určeným rozhraním INavigationService
. Tím se zabrání režii při vkládání objektu NavigationService
z kontejneru injektáže závislostí Autofac do každé třídy modelu zobrazení.
Zpracování žádostí o navigaci
Xamarin.FormsNavigationPage
poskytuje třídu, která implementuje hierarchické navigační prostředí, ve kterém uživatel může podle potřeby procházet stránky, dopředu a dozadu. Další informace o hierarchické navigaci naleznete v tématu Hierarchická navigace.
Místo přímého použití NavigationPage
třídy eShopOnContainers aplikace zabalí NavigationPage
třídu do CustomNavigationView
třídy, jak je znázorněno v následujícím příkladu kódu:
public partial class CustomNavigationView : NavigationPage
{
public CustomNavigationView() : base()
{
InitializeComponent();
}
public CustomNavigationView(Page root) : base(root)
{
InitializeComponent();
}
}
Účelem tohoto zabalení je snadné stylování NavigationPage
instance uvnitř souboru XAML pro třídu.
Navigace se provádí uvnitř tříd modelu zobrazení vyvoláním jedné z NavigateToAsync
metod a určením typu modelu zobrazení pro stránku, na kterou se přechází, jak je znázorněno v následujícím příkladu kódu:
await NavigationService.NavigateToAsync<MainViewModel>();
Následující příklad kódu ukazuje NavigateToAsync
metody poskytované NavigationService
třídou:
public Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase
{
return InternalNavigateToAsync(typeof(TViewModel), null);
}
public Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase
{
return InternalNavigateToAsync(typeof(TViewModel), parameter);
}
Každá metoda umožňuje jakoukoli třídu modelu zobrazení, která je odvozena od ViewModelBase
třídy, provádět hierarchickou navigaci vyvoláním InternalNavigateToAsync
metody. Druhá NavigateToAsync
metoda navíc umožňuje zadat navigační data jako argument předaný modelu zobrazení, do kterého se přechází, kde se obvykle používá k provedení inicializace. Další informace naleznete v tématu Předávání parametrů během navigace.
Metoda InternalNavigateToAsync
spustí požadavek navigace a je znázorněn v následujícím příkladu kódu:
private async Task InternalNavigateToAsync(Type viewModelType, object parameter)
{
Page page = CreatePage(viewModelType, parameter);
if (page is LoginView)
{
Application.Current.MainPage = new CustomNavigationView(page);
}
else
{
var navigationPage = Application.Current.MainPage as CustomNavigationView;
if (navigationPage != null)
{
await navigationPage.PushAsync(page);
}
else
{
Application.Current.MainPage = new CustomNavigationView(page);
}
}
await (page.BindingContext as ViewModelBase).InitializeAsync(parameter);
}
private Type GetPageTypeForViewModel(Type viewModelType)
{
var viewName = viewModelType.FullName.Replace("Model", string.Empty);
var viewModelAssemblyName = viewModelType.GetTypeInfo().Assembly.FullName;
var viewAssemblyName = string.Format(
CultureInfo.InvariantCulture, "{0}, {1}", viewName, viewModelAssemblyName);
var viewType = Type.GetType(viewAssemblyName);
return viewType;
}
private Page CreatePage(Type viewModelType, object parameter)
{
Type pageType = GetPageTypeForViewModel(viewModelType);
if (pageType == null)
{
throw new Exception($"Cannot locate page type for {viewModelType}");
}
Page page = Activator.CreateInstance(pageType) as Page;
return page;
}
Metoda InternalNavigateToAsync
provádí navigaci na model zobrazení tím, že nejprve zavolá metodu CreatePage
. Tato metoda vyhledá zobrazení, které odpovídá zadanému typu modelu zobrazení, a vytvoří a vrátí instanci tohoto typu zobrazení. Umístění zobrazení odpovídající typu modelu zobrazení používá konvenční přístup, který předpokládá, že:
- Zobrazení jsou ve stejném sestavení jako typy modelů zobrazení.
- Zobrazení jsou v . Zobrazení podřízeného oboru názvů
- Zobrazit modely jsou v . Podřízený obor názvů ViewModels
- Názvy zobrazení odpovídají názvům modelů s odebraným textem Model.
Když se vytvoří instance zobrazení, je přidruženo k příslušnému modelu zobrazení. Další informace o tom, jak k tomu dochází, naleznete v tématu Automatické vytvoření modelu zobrazení pomocí lokátoru modelu zobrazení.
Pokud je LoginView
vytvořené zobrazení , je zabaleno uvnitř nové instance CustomNavigationView
třídy a přiřazeno Application.Current.MainPage
k vlastnosti. CustomNavigationView
V opačném případě se instance načte a za předpokladu, že není null, PushAsync
metoda je vyvolána pro odeslání zobrazení vytvořeného do navigačního zásobníku. Pokud je však načtená CustomNavigationView
instance , je vytvořené zobrazení zabaleno uvnitř nové instance CustomNavigationView
třídy a přiřazeno k Application.Current.MainPage
vlastnosti.null
Tento mechanismus zajišťuje, že během navigace se stránky správně přidají do navigačního zásobníku, když je prázdný a kdy obsahuje data.
Tip
Zvažte ukládání stránek do mezipaměti. Ukládání stránek do mezipaměti vede ke spotřebě paměti pro zobrazení, která se aktuálně nezobrazují. Bez ukládání stránky do mezipaměti ale znamená, že analýza a konstrukce stránky a jeho modelu zobrazení se projeví při každém přechodu na novou stránku, což může mít dopad na výkon pro složitou stránku. Pro dobře navrženou stránku, která nepoužívá nadměrný počet ovládacích prvků, by měl být výkon dostatečný. Ukládání stránek do mezipaměti ale může pomoct v případě, že dojde k pomalému načítání stránek.
Po vytvoření a přechodu na InitializeAsync
zobrazení se spustí metoda přidruženého modelu zobrazení. Další informace naleznete v tématu Předávání parametrů během navigace.
Navigace při spuštění aplikace
Při spuštění InitNavigation
aplikace je vyvolána metoda ve App
třídě. Následující příklad kódu ukazuje tuto metodu:
private Task InitNavigation()
{
var navigationService = ViewModelLocator.Resolve<INavigationService>();
return navigationService.InitializeAsync();
}
Metoda vytvoří nový NavigationService
objekt v kontejneru injektáže závislostí Autofac a před vyvoláním metody vrátí odkaz na něj InitializeAsync
.
Poznámka:
INavigationService
Když rozhraní je vyřešeno ViewModelBase
třídou, kontejner vrátí odkaz na NavigationService
objekt, který byl vytvořen při InitNavigation metoda je vyvolána.
Následující příklad kódu ukazuje metodu NavigationService
InitializeAsync
:
public Task InitializeAsync()
{
if (string.IsNullOrEmpty(Settings.AuthAccessToken))
return NavigateToAsync<LoginViewModel>();
else
return NavigateToAsync<MainViewModel>();
}
Přejde MainView
se na to, jestli má aplikace přístupový token uložený v mezipaměti, který se používá k ověřování. V opačném případě se LoginView
na něj přejde.
Další informace o kontejneru injektáže závislostí autofac naleznete v tématu Úvod do injektáže závislostí.
Předávání parametrů během navigace
Jedna z NavigateToAsync
metod určených INavigationService
rozhraním umožňuje zadat navigační data jako argument předaný modelu zobrazení, do kterého se přechází, kde se obvykle používá k provedení inicializace.
Třída například ProfileViewModel
obsahuje spuštěnou OrderDetailCommand
třídu, když uživatel vybere objednávku na ProfileView
stránce. Následně se spustí OrderDetailAsync
metoda, která je zobrazena v následujícím příkladu kódu:
private async Task OrderDetailAsync(Order order)
{
await NavigationService.NavigateToAsync<OrderDetailViewModel>(order);
}
Tato metoda vyvolá navigaci na OrderDetailViewModel
, předávání Order
instance, která představuje pořadí, které uživatel vybral na ProfileView
stránce. NavigationService
Když třída vytvoří OrderDetailView
, OrderDetailViewModel
třída je vytvořena a přiřazena k zobrazení BindingContext
. Po přechodu na metodu OrderDetailView
InternalNavigateToAsync
spustí InitializeAsync
metodu přidruženého modelu zobrazení zobrazení.
Metoda InitializeAsync
je definována ve ViewModelBase
třídě jako metoda, která lze přepsat. Tato metoda určuje object
argument, který představuje data, která se mají předat modelu zobrazení během operace navigace. Proto si prohlédněte třídy modelu, které chtějí přijímat data z navigační operace, poskytují vlastní implementaci InitializeAsync
metody k provedení požadované inicializace. Následující příklad kódu ukazuje metodu InitializeAsync
OrderDetailViewModel
z třídy:
public override async Task InitializeAsync(object navigationData)
{
if (navigationData is Order)
{
...
Order = await _ordersService.GetOrderAsync(
Convert.ToInt32(order.OrderNumber), authToken);
...
}
}
Tato metoda načte Order
instanci, která byla předána do modelu zobrazení během operace navigace, a používá ji k načtení úplných podrobností objednávky z OrderService
instance.
Vyvolání navigace pomocí chování
Navigace se obvykle aktivuje ze zobrazení interakcí uživatele. Například provede LoginView
navigaci po úspěšném ověření. Následující příklad kódu ukazuje, jak je navigace vyvolána chováním:
<WebView ...>
<WebView.Behaviors>
<behaviors:EventToCommandBehavior
EventName="Navigating"
EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"
Command="{Binding NavigateCommand}" />
</WebView.Behaviors>
</WebView>
Za běhu EventToCommandBehavior
bude reagovat na interakci s .WebView
WebView
Když přejdete na webovou stránku, Navigating
aktivuje se událost, která spustí NavigateCommand
v souboru LoginViewModel
. Ve výchozím nastavení se argumenty události události předávají příkazu. Tato data se převedou tak, jak se předávají mezi zdrojem a cílem převaděčem zadaným ve EventArgsConverter
vlastnosti, která vrací Url
z WebNavigatingEventArgs
. Proto při NavigationCommand
spuštění je adresa URL webové stránky předána jako parametr registrovanému Action
.
Následně provede NavigationCommand
metodu NavigateAsync
, která je zobrazena v následujícím příkladu kódu:
private async Task NavigateAsync(string url)
{
...
await NavigationService.NavigateToAsync<MainViewModel>();
await NavigationService.RemoveLastFromBackStackAsync();
...
}
Tato metoda vyvolá navigaci na MainViewModel
a následující navigaci odebere LoginView
stránku z navigačního zásobníku.
Potvrzení nebo zrušení navigace
Aplikace může během operace navigace potřebovat interakci s uživatelem, aby uživatel mohl potvrdit nebo zrušit navigaci. To může být nutné například v případě, že se uživatel pokusí přejít před úplným dokončením stránky pro zadávání dat. V takovém případě by aplikace měla poskytnout oznámení, které uživateli umožní přejít mimo stránku nebo zrušit navigační operaci předtím, než k ní dojde. Toho lze dosáhnout ve třídě modelu zobrazení pomocí odpovědi z oznámení k řízení, zda je vyvolána nebo není vyvolána navigace.
Shrnutí
Xamarin.Forms zahrnuje podporu navigace na stránce, která obvykle vede k interakci uživatele s uživatelským rozhraním nebo ze samotné aplikace v důsledku interních změn stavu řízeného logikou. Navigace ale může být složitá pro implementaci v aplikacích, které používají model MVVM.
Tato kapitola představila NavigationService
třídu, která se používá k zobrazení modelu první navigace z modelů zobrazení. Umístění navigační logiky do tříd modelu zobrazení znamená, že logiku je možné provádět prostřednictvím automatizovaných testů. Model zobrazení pak může implementovat logiku pro řízení navigace, aby se zajistilo, že se vynucují určitá obchodní pravidla.