Xamarin.Forms Prism Navigation

In Xamarin.Forms werden Dialoge in einem Stack verwaltet. Soll ein neuer angezeigt werden, wird er erzeugt und auf den Stack gelegt (Push). Zur vorherigen Ansicht kehrt man zurück, indem der aktuelle Dialog aus dem Stack entfernt wird (Pop). Diese Navigation findet normalerweise über die Navigation property der Page-Klasse und damit innerhalb der UI-Komponente statt. Üblich ist das Navigieren per Event handler im Code behind:

Xamarin.Forms Prism Navigation- 30102018-Mobile-15KB, generic.de AG

Abbildung 1 / Bildquelle: Stefan Fritz, generic.de AG

Der Datenaustausch zwischen den Seiten ist in diesem Beispiel per BindingContext property gelöst.

Bei Berücksichtigung von MVVM und um möglichst viel meines Codes testbar zu halten, möchte ich meine Code behind Dateien aber möglichst leer halten. Dafür hält Prism eine Alternative in Form des Navigation Service bereit.

Prism Navigation

Um die Navigationslogik aus der View heraus und ins ViewModel hinein zu bekommen, bietet Prism einen eigenen Service zur Navigation zwischen den Seiten einer App an. Als Navigationsziel wird dabei der Name einer View als URI oder string angegeben. Relative URIs legen die neue View oben auf den Stack, absolute leeren ihn zuerst und das Navigationsziel wird als einzige View auf den Stack gelegt.

Um uns das Leben zu erleichtern, wurden noch einige Sonderfunktionen eingebaut. Beispielsweise können einzelne Views aus dem Stack entfernt werden (/../NextPage wirft die aktuelle View vom Stack und legt dann die NextPage darauf).

Um Daten zwischen den Dialogen auszutauschen, kann bei der Navigation ein NavigationParameters Objekt mitgegeben werden, das unter der Haube einfach ein Dictionary<string, object> ist.

Xamarin.Forms Prism Navigation- 30102018-Mobile-10KB, generic.de AG

Abbildung 2 / Bildquelle: Stefan Fritz, generic.de AG

Um auf die NavigationParameters zuzugreifen, muss das Ziel ViewModel das Interface INavigationAware implementieren. Die Methoden OnNavigatingTo (vor Navigation) und OnNavigatedTo (nach Navigation) werden dann im Navigationsprozess aufgerufen und erlauben den Zugriff auf die NavigationParameters.

Xamarin.Forms Prism Navigation- 30102018-Mobile-9KB, generic.de AG

Abbildung 3 / Bildquelle: Stefan Fritz, generic.de AG

Dies ist nur ein grober Umriss der Möglichkeiten, die die Prism Navigation bietet.

Hier gibt es mehr Details sowie eine Alternative.

In sämtlichen Beispielen und Anleitungen, die ich bisher gefunden habe, wird der Prism NavigationService direkt in den ViewModels verwendet.

Obwohl dadurch gegenüber der Xamarin.Forms Standardnavigation im Code behind der einzelnen Dialoge einiges gewonnen ist, gefällt mir dieser Aufbau aus den folgenden Gründen nicht:

  1. Das Navigationsziel wird über seinen Namen bestimmt. Wird ein Name geändert, müssen alle Navigationskommandos zu der View händisch gefunden und angepasst werden. Es handelt sich um eine versteckte Abhängigkeit und ViewModels und deren Funktionsfähigkeit sollte nicht von Views abhängen.
  2. Der Anwendungsablauf und die Navigationslogik ist über alle ViewModels verteilt.
  3. Das Navigationsziel kann nicht mitteilen, welche Daten es als Navigationsparameter benötigt, um funktionieren zu können. Will ich zu einem Dialog navigieren, muss ich zuerst den Code seines ViewModels anschauen, um herauszufinden, welche Daten mit welchen Keys erwartet werden. Wird das vergessen, treten Fehler erst zur Laufzeit auf oder – noch schlimmer – die App verhält sich unbemerkt nicht wie erwartet.
  4. Die Navigationsparameter werden nicht in typischer Form eines Dictionary<string, object> übergeben.

Diese Überlegungen waren der Anlass für mich, den NavigationService von Prism in meinen Apps durch eigenes Abstrahieren zu kapseln. Dazu mehr im nächsten Post.