Teil 2: Windows 10 Apps mit MVVMbasics


Gastbeitrag von Andreas Kuntner

Dieser Artikel ist der zweite Teil einer dreiteiligen Serie.

Andreas Kuntner arbeitet als .NET Entwickler mit Schwerpunkt auf Client-, UI- und Mobile Development, und betreut in seiner Freizeit das MVVMbasics Framework und den Developer-Blog http://blog.mobilemotion.eu/

... und Action!

Genug von der trockenen Theorie , jetzt wird es Zeit dass unsere App auch etwas tut!

Stellen wir uns eine App mit zwei Seiten vor, die MainPage wird beim Start angezeigt, und von dieser kann man weiter auf eine DetailPage navigieren. Erstellen wir also eine zweite Page mit Namen "DetailPage", die ebenfalls von BackButtonAwareBaseView abgeleitet ist und IBindableView implementiert:

1
2
3
4
5
6
7
8
public sealed partial class DetailPage : BackButtonAwareBaseView, IBindableView<DetailViewmodel>
{
    public DetailPage()
    {
        this.InitializeComponent();
    }
    public DetailViewmodel Vm { get; set; }
}

Das Property Vm muss ebenfalls in jeder View definiert sein, dieses werden wir bald zum Binden von Daten brauchen.

Als Viewmodel-Typ geben wir "DetailViewmodel" an - dieses Viewmodel muss aber ebenfalls erst erstellt werden, und zwar im vorhandenen Ordner Viewmodels des Portable Class Library Projekts.

Primäre Aufgabe eines Viewmodels ist, wie gesagt, der View Daten für die Anzeige zur Verfügung zu stellen. Füllen wir das Viewmodel also mit einem Property vom Typ string, das dann auf der Page zu sehen sein soll:

1
2
3
4
5
6
7
8
9
public class DetailViewmodel : NavigatorAwareBaseViewmodel
{
    [MvvmBindable]
    public string MyText { get; set; }
    public DetailViewmodel(INavigatorService navigatorService) : base(navigatorService)
    {
        MyText = "Hello World!";
    }
}

Generell gilt: Die View kann auf alle Daten ihres Viewmodels zugreifen, die als Property deklariert und als public markiert sind. Außerdem sollte das Attribute [MvvmBindable] vor der Property-Deklaration stehen, denn nur dadurch wird die View auch über jede Änderung der Daten informiert.

In der Page selbst kann dieser Wert angezeigt werden, dazu verwenden wir Data Binding. Aufgrund der wesentlich besseren Performance sollte statt dem herkömmlichen {Binding ...} das in UWP neu eingeführte kompilierte Binding verwendet werden, dazu machen wir uns das zuvor definierte Vm Property zunutze:

1
2
3
4
5
6
7
8
9
<views:BackButtonAwareBaseView
    x:Class="MVVMbasics_demo.App.Views.DetailPage"
    xmlns:views="using:MVVMbasics_demo.App.Views">
    <TextBlock Text="{x:Bind Vm.MyText, Mode=OneWay}"/>
</views:BackButtonAwareBaseView>

Ein wesentlicher Unterscheid von Windows 10 zu herkömmlichen Universal Apps ist der Data Binding Modus: Bisher war dieser standardmäßig OneWay oder TwoWay (je nach Art des User Controls), jetzt ist er immer OneTime was bedeutet dass jedes Binding nur einmal beim Laden der Seite aufgelöst wird. Aus diesem Grund empfiehlt es sich, Mode=OneWay zu ergänzen.

Commanding:

Wie kommt diese View jetzt aber zur Anzeige? Öffnen wir zunächst das MainViewmodel: Hier ist bereits ein ähnliches Property definiert, das wir löschen können, ebenso (wie schon erwähnt) alle Verweise auf SamplePlatformspecificService und SamplePortableService, und die OnNavigatedXyz-Methoden. Übrig bleibt das folgende Gerüst:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public sealed class MainViewmodel : NavigatorAwareBaseViewmodel
{
    private readonly INavigatorService _navigatorService;
    
    public BaseCommand SampleCommand { get; set; }
    
    public MainViewmodel(INavigatorService navigatorService) : base(navigatorService)
    {
        _navigatorService = navigatorService;
        SampleCommand = CreateCommand(SampleMethod);
    }
    private void SampleMethod()
    {
        //TODO
    }
}

Der Hintergrund: Die zweite Aufgabe eines Viewmodels (nebem den Aufbereiten und Bereitstellen von Daten, wie oben gezeigt) ist es, Befehle von der View entgegenzunehmen und Logik auszuführen. Diese Befehle werden in Form von Commands übertragen, in MVVMbasics handelt es sich dabei um Objekte vom Typ BaseCommand.

Jedes dieser Commands muss als public Property deklariert sein (damit es für die View erreichbar ist), sowie mit einer Viewmodel-internen Methode verknüpft sein (diese Verknüpfung erstellen wir im Constructor durch Aufruf der CreateCommand-Methode).

Nutzen wir unser SampleCommand, um von der MainPage auf die DetailPage zu wechseln. Dafür brauchst es nur den folgenden Aufruf innerhalb der SampleMethod, die gestartet wird wann immer in der View das SampleCommand ausgelöst wird:

1
2
3
4
private void SampleMethod()
{
    _navigatorService.NavigateTo<DetailViewmodel>();
}

Da das NavigatorService ja über alle View-Viewmodel-Verknüpfungen Bescheid weiß, nutzen wir es auch für die Navigation: Der NavigateTo-Methode wird der Typ des gewünschten Ziel-Viewmodels mitgegeben, und automatisch wird die damit verknüpfte View am Bildschirm angezeigt!

In der View selbst ist bereits ein Beispiel-Button implementiert der an dieses Command bindet:

1
<Button Command="{x:Bind Vm.SampleCommand}">Show detail page</Button>

Sobald der User diesen Button antippt bzw. anklickt, wird das Command ausgeführt, und im Viewmodel wird die Methode SampleMethod aufgerufen, was dazu führt dass die Anzeige auf die DetailPage springt


Skip to main content