Teil 5. Von Datenbindungen zu MVVM
Das Architekturmuster Model-View-ViewModel (MVVM) wurde mit XAML erfunden. Das Muster erzwingt eine Trennung zwischen drei Softwareebenen – der XAML-Benutzeroberfläche, die als Ansicht bezeichnet wird; die zugrunde liegenden Daten, die als Modell bezeichnet werden; und eine Zwischenschaltung zwischen der Ansicht und dem Modell, die als ViewModel bezeichnet wird. Die Ansicht und das ViewModel sind häufig über datenbindungen verbunden, die in der XAML-Datei definiert sind. Der BindingContext für die Ansicht ist in der Regel eine Instanz des ViewModel.
Einfaches ViewModel
Als Einführung in ViewModels betrachten wir zunächst ein Programm ohne ein Programm.
Weiter oben haben Sie gesehen, wie Sie eine neue XML-Namespacedeklaration definieren, damit eine XAML-Datei auf Klassen in anderen Assemblys verweist. Hier ist ein Programm, das eine XML-Namespacedeklaration für den System
Namespace definiert:
xmlns:sys="clr-namespace:System;assembly=netstandard"
Das Programm kann verwendenx:Static
, um das aktuelle Datum und die aktuelle Uhrzeit aus der statischen DateTime.Now
Eigenschaft abzurufen und diesen DateTime
Wert auf ein StackLayout
:BindingContext
<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>
BindingContext
ist eine spezielle Eigenschaft: Wenn Sie das BindingContext
Element für ein Element festlegen, wird es von allen untergeordneten Elementen dieses Elements geerbt. Dies bedeutet, dass alle untergeordneten Elemente StackLayout
dieses Objekts gleich BindingContext
sind und sie einfache Bindungen an Eigenschaften dieses Objekts enthalten können.
Im One-Shot DateTime-Programm enthalten zwei der untergeordneten Elemente Bindungen an Eigenschaften dieses DateTime
Werts, aber zwei andere untergeordnete Elemente enthalten Bindungen, die scheinbar einen Bindungspfad fehlen. Dies bedeutet, dass der Wert selbst für folgendes DateTime
StringFormat
verwendet wird:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="XamlSamples.OneShotDateTimePage"
Title="One-Shot DateTime Page">
<StackLayout BindingContext="{x:Static sys:DateTime.Now}"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label Text="{Binding Year, StringFormat='The year is {0}'}" />
<Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
<Label Text="{Binding Day, StringFormat='The day is {0}'}" />
<Label Text="{Binding StringFormat='The time is {0:T}'}" />
</StackLayout>
</ContentPage>
Das Problem besteht darin, dass das Datum und die Uhrzeit einmal festgelegt werden, wenn die Seite zum ersten Mal erstellt wird und sich nie ändern:
Eine XAML-Datei kann eine Uhr anzeigen, die immer die aktuelle Uhrzeit anzeigt, benötigt jedoch Code, um hilfe zu erhalten. Beim Denken in Bezug auf MVVM sind Modell und ViewModel Klassen, die vollständig im Code geschrieben werden. Die Ansicht ist häufig eine XAML-Datei, die auf eigenschaften verweist, die im ViewModel über Datenbindungen definiert sind.
Ein richtiges Modell ist unwissend vom ViewModel, und ein ordnungsgemäßes ViewModel ist unwissend von der Ansicht. Ein Programmierer passt jedoch häufig die Datentypen an, die vom ViewModel auf die Datentypen zugeschnitten sind, die bestimmten Benutzeroberflächen zugeordnet sind. Wenn beispielsweise ein Modell auf eine Datenbank zugreift, die 8-Bit-ASCII-Zeichenfolgen enthält, muss das ViewModel zwischen diesen Zeichenfolgen in Unicode-Zeichenfolgen konvertieren, um die ausschließliche Verwendung von Unicode auf der Benutzeroberfläche zu berücksichtigen.
In einfachen Beispielen für MVVM (z. B. die hier gezeigten) gibt es häufig kein Modell, und das Muster umfasst nur ein View- und ViewModel-Objekt, das mit Datenbindungen verknüpft ist.
Hier ist ein ViewModel für eine Uhr mit nur einer einzigen Eigenschaft namens DateTime
, die diese DateTime
Eigenschaft jede Sekunde aktualisiert:
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;
public event PropertyChangedEventHandler PropertyChanged;
public ClockViewModel()
{
this.DateTime = DateTime.Now;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
this.DateTime = DateTime.Now;
return true;
});
}
public DateTime DateTime
{
set
{
if (dateTime != value)
{
dateTime = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
}
get
{
return dateTime;
}
}
}
}
ViewModels implementieren in der Regel die INotifyPropertyChanged
Schnittstelle, was bedeutet, dass die Klasse ein PropertyChanged
Ereignis auslöst, wenn eine seiner Eigenschaften geändert wird. Der Datenbindungsmechanismus fügt Xamarin.Forms einen Handler an dieses PropertyChanged
Ereignis an, sodass er benachrichtigt werden kann, wenn sich eine Eigenschaft ändert und das Ziel mit dem neuen Wert aktualisiert wird.
Eine Uhr, die auf diesem ViewModel basiert, kann so einfach wie folgt sein:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.ClockPage"
Title="Clock Page">
<Label Text="{Binding DateTime, StringFormat='{0:T}'}"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.BindingContext>
<local:ClockViewModel />
</Label.BindingContext>
</Label>
</ContentPage>
Beachten Sie, wie die ClockViewModel
Einstellung auf die BindingContext
Label
verwendung von Eigenschaftselementtags festgelegt ist. Alternativ können Sie die ClockViewModel
In einer Resources
Sammlung instanziieren und auf die BindingContext
über eine StaticResource
Markuperweiterung festlegen. Oder die CodeBehind-Datei kann das ViewModel instanziieren.
Die Markuperweiterung Binding
der Text
-Eigenschaft des Label
formatiert die DateTime
-Eigenschaft. Dies ist die Anzeige:
Es ist auch möglich, auf einzelne Eigenschaften der DateTime
Eigenschaft des ViewModel zuzugreifen, indem die Eigenschaften durch Punkte getrennt werden:
<Label Text="{Binding DateTime.Second, StringFormat='{0}'}" … >
Interaktive MVVM
MVVM wird häufig mit bidirektionale Datenbindungen für eine interaktive Ansicht basierend auf einem zugrunde liegenden Datenmodell verwendet.
Hier ist eine Klasse mit dem Namen HslViewModel
, die einen Color
Wert in Hue
, Saturation
und Luminosity
Werte konvertiert und umgekehrt:
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace XamlSamples
{
public class HslViewModel : INotifyPropertyChanged
{
double hue, saturation, luminosity;
Color color;
public event PropertyChangedEventHandler PropertyChanged;
public double Hue
{
set
{
if (hue != value)
{
hue = value;
OnPropertyChanged("Hue");
SetNewColor();
}
}
get
{
return hue;
}
}
public double Saturation
{
set
{
if (saturation != value)
{
saturation = value;
OnPropertyChanged("Saturation");
SetNewColor();
}
}
get
{
return saturation;
}
}
public double Luminosity
{
set
{
if (luminosity != value)
{
luminosity = value;
OnPropertyChanged("Luminosity");
SetNewColor();
}
}
get
{
return luminosity;
}
}
public Color Color
{
set
{
if (color != value)
{
color = value;
OnPropertyChanged("Color");
Hue = value.Hue;
Saturation = value.Saturation;
Luminosity = value.Luminosity;
}
}
get
{
return color;
}
}
void SetNewColor()
{
Color = Color.FromHsla(Hue, Saturation, Luminosity);
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Änderungen an den Hue
, Saturation
und Luminosity
Eigenschaften führen dazu, dass sich die Color
Eigenschaft ändert, und Änderungen Color
bewirken, dass sich die anderen drei Eigenschaften ändern. Dies mag wie eine Endlosschleife aussehen, mit der Ausnahme, dass die Klasse das PropertyChanged
Ereignis nicht aufruft, es sei denn, die Eigenschaft wurde geändert. Dadurch wird die andernfalls unkontrollierbare Feedbackschleife beendet.
Die folgende XAML-Datei enthält eine BoxView
Eigenschaft, deren Color
Eigenschaft an die Color
Eigenschaft des ViewModel gebunden ist, und drei Slider
und drei Label
Ansichten, die an die Hue
Eigenschaften und Saturation
Luminosity
Eigenschaften gebunden sind:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.HslColorScrollPage"
Title="HSL Color Scroll Page">
<ContentPage.BindingContext>
<local:HslViewModel Color="Aqua" />
</ContentPage.BindingContext>
<StackLayout Padding="10, 0">
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Hue, Mode=TwoWay}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Saturation, Mode=TwoWay}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Luminosity, Mode=TwoWay}" />
</StackLayout>
</ContentPage>
Die Bindung an jede Label
ist Standard OneWay
. Der Wert muss nur angezeigt werden. Aber die Bindung an jedem Slider
ist TwoWay
. Dadurch kann das Slider
ViewModel initialisiert werden. Beachten Sie, dass die Color
Eigenschaft festgelegt Aqua
ist, wenn das ViewModel instanziiert wird. Eine Änderung der Slider
Eigenschaft muss jedoch auch einen neuen Wert für die Eigenschaft im ViewModel festlegen, wodurch dann eine neue Farbe berechnet wird.
Befehle mit ViewModels
In vielen Fällen ist das MVVM-Muster auf die Manipulation von Datenelementen beschränkt: Benutzeroberflächenobjekte in den View parallelen Datenobjekten im ViewModel.
Manchmal muss die Ansicht jedoch Schaltflächen enthalten, die verschiedene Aktionen im ViewModel auslösen. Das ViewModel darf jedoch keine Handler für die Schaltflächen enthalten Clicked
, da das ViewModel an ein bestimmtes Benutzeroberflächenparadigma gebunden würde.
Damit ViewModels unabhängiger von bestimmten Benutzeroberflächenobjekten sein können, aber trotzdem methoden innerhalb des ViewModel aufgerufen werden können, ist eine Befehlsschnittstelle vorhanden. Diese Befehlsschnittstelle wird von den folgenden Elementen in unterstützt:Xamarin.Forms
Button
MenuItem
ToolbarItem
SearchBar
TextCell
(und damit auchImageCell
)ListView
TapGestureRecognizer
Mit Ausnahme des SearchBar
Elements definieren ListView
diese Elemente zwei Eigenschaften:
Command
vom TypSystem.Windows.Input.ICommand
CommandParameter
vom TypObject
Die SearchBar
Definierten SearchCommand
und SearchCommandParameter
Eigenschaften, während die ListView
Eigenschaft vom RefreshCommand
Typ ICommand
definiert wird.
Die ICommand
Schnittstelle definiert zwei Methoden und ein Ereignis:
void Execute(object arg)
bool CanExecute(object arg)
event EventHandler CanExecuteChanged
Das ViewModel kann Eigenschaften vom Typ ICommand
definieren. Sie können diese Eigenschaften dann an die Command
-Eigenschaft jedes Button
-Elements oder anderen Elements binden, oder vielleicht an eine benutzerdefinierte Ansicht, die diese Schnittstelle implementiert. Sie können optional die CommandParameter
Eigenschaft festlegen, um einzelne Button
Objekte (oder andere Elemente) zu identifizieren, die an diese ViewModel-Eigenschaft gebunden sind. Intern ruft Button
die Methode Execute
auf, wenn der Benutzer auf Button
tippt, und übergibt der Methode Execute
an sein CommandParameter
.
Die CanExecute
-Methode und das CanExecuteChanged
-Ereignis werden für Fälle verwendet, in denen ein Button
-Tippen derzeit ungültig sein könnte. In diesem Fall sollte sich Button
selbst deaktivieren. Die Button
Aufrufe CanExecute
, wenn die Command
Eigenschaft zum ersten Mal festgelegt wird und wann immer das CanExecuteChanged
Ereignis ausgelöst wird. Wenn CanExecute
false
zurückgibt, deaktiviert sich Button
selbst und erzeugt keine Execute
-Aufrufe.
Um Hilfe beim Hinzufügen von Befehlen zu Ihren ViewModels zu ermöglichen, definieren Sie zwei Klassen, Xamarin.Forms die folgendes implementieren ICommand
: Command
und Command<T>
wo T
befindet sich der Typ der Argumente für Execute
und CanExecute
. Diese beiden Klassen definieren mehrere Konstruktoren sowie eine ChangeCanExecute
Methode, die das ViewModel aufrufen kann, um das Objekt zum Auslösen des Command
CanExecuteChanged
Ereignisses zu erzwingen.
Hier ist ein ViewModel für eine einfache Wähltastatur, die für die Eingabe von Telefonnummern vorgesehen ist. Beachten Sie, dass die und CanExecute
die Execute
Methode direkt im Konstruktor als Lambda-Funktionen definiert sind:
using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;
namespace XamlSamples
{
class KeypadViewModel : INotifyPropertyChanged
{
string inputString = "";
string displayText = "";
char[] specialChars = { '*', '#' };
public event PropertyChangedEventHandler PropertyChanged;
// Constructor
public KeypadViewModel()
{
AddCharCommand = new Command<string>((key) =>
{
// Add the key to the input string.
InputString += key;
});
DeleteCharCommand = new Command(() =>
{
// Strip a character from the input string.
InputString = InputString.Substring(0, InputString.Length - 1);
},
() =>
{
// Return true if there's something to delete.
return InputString.Length > 0;
});
}
// Public properties
public string InputString
{
protected set
{
if (inputString != value)
{
inputString = value;
OnPropertyChanged("InputString");
DisplayText = FormatText(inputString);
// Perhaps the delete button must be enabled/disabled.
((Command)DeleteCharCommand).ChangeCanExecute();
}
}
get { return inputString; }
}
public string DisplayText
{
protected set
{
if (displayText != value)
{
displayText = value;
OnPropertyChanged("DisplayText");
}
}
get { return displayText; }
}
// ICommand implementations
public ICommand AddCharCommand { protected set; get; }
public ICommand DeleteCharCommand { protected set; get; }
string FormatText(string str)
{
bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
string formatted = str;
if (hasNonNumbers || str.Length < 4 || str.Length > 10)
{
}
else if (str.Length < 8)
{
formatted = String.Format("{0}-{1}",
str.Substring(0, 3),
str.Substring(3));
}
else
{
formatted = String.Format("({0}) {1}-{2}",
str.Substring(0, 3),
str.Substring(3, 3),
str.Substring(6));
}
return formatted;
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Dieses ViewModel geht davon aus, dass die Eigenschaft an die AddCharCommand
Command
Eigenschaft mehrerer Schaltflächen gebunden ist (oder etwas anderes, das über eine Befehlsschnittstelle verfügt), von denen jede durch die CommandParameter
. Diese Tasten fügen Zeichen zu einer InputString
-Eigenschaft hinzu, die dann als Telefonnummer für die DisplayText
-Eigenschaft formatiert wird.
Es gibt auch eine zweite Eigenschaft des Typs ICommand
namens DeleteCharCommand
. Dies ist an eine Rücktasten-Schaltfläche gebunden, aber die Schaltfläche sollte deaktiviert werden, wenn keine Zeichen zu löschen sind.
Die folgende Wähltastatur ist nicht so visuell anspruchsvoll wie es sein könnte. Stattdessen wurde das Markup auf ein Minimum reduziert, um die Verwendung der Befehlsschnittstelle deutlicher zu veranschaulichen:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.KeypadPage"
Title="Keypad Page">
<Grid HorizontalOptions="Center"
VerticalOptions="Center">
<Grid.BindingContext>
<local:KeypadViewModel />
</Grid.BindingContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<!-- Internal Grid for top row of items -->
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Frame Grid.Column="0"
OutlineColor="Accent">
<Label Text="{Binding DisplayText}" />
</Frame>
<Button Text="⇦"
Command="{Binding DeleteCharCommand}"
Grid.Column="1"
BorderWidth="0" />
</Grid>
<Button Text="1"
Command="{Binding AddCharCommand}"
CommandParameter="1"
Grid.Row="1" Grid.Column="0" />
<Button Text="2"
Command="{Binding AddCharCommand}"
CommandParameter="2"
Grid.Row="1" Grid.Column="1" />
<Button Text="3"
Command="{Binding AddCharCommand}"
CommandParameter="3"
Grid.Row="1" Grid.Column="2" />
<Button Text="4"
Command="{Binding AddCharCommand}"
CommandParameter="4"
Grid.Row="2" Grid.Column="0" />
<Button Text="5"
Command="{Binding AddCharCommand}"
CommandParameter="5"
Grid.Row="2" Grid.Column="1" />
<Button Text="6"
Command="{Binding AddCharCommand}"
CommandParameter="6"
Grid.Row="2" Grid.Column="2" />
<Button Text="7"
Command="{Binding AddCharCommand}"
CommandParameter="7"
Grid.Row="3" Grid.Column="0" />
<Button Text="8"
Command="{Binding AddCharCommand}"
CommandParameter="8"
Grid.Row="3" Grid.Column="1" />
<Button Text="9"
Command="{Binding AddCharCommand}"
CommandParameter="9"
Grid.Row="3" Grid.Column="2" />
<Button Text="*"
Command="{Binding AddCharCommand}"
CommandParameter="*"
Grid.Row="4" Grid.Column="0" />
<Button Text="0"
Command="{Binding AddCharCommand}"
CommandParameter="0"
Grid.Row="4" Grid.Column="1" />
<Button Text="#"
Command="{Binding AddCharCommand}"
CommandParameter="#"
Grid.Row="4" Grid.Column="2" />
</Grid>
</ContentPage>
Die Command
Eigenschaft des ersten Button
, das in diesem Markup angezeigt wird, ist an das DeleteCharCommand
Element gebunden; der Rest ist mit AddCharCommand
dem CommandParameter
Zeichen verbunden, das im Button
Gesicht angezeigt wird. Hier ist das Programm in Aktion:
Aufrufen asynchroner Methoden
Befehle können auch asynchrone Methoden aufrufen. Dies wird mithilfe der async
und await
Schlüsselwort (keyword) erreicht, wenn Sie die Execute
Methode angeben:
DownloadCommand = new Command (async () => await DownloadAsync ());
Dies gibt an, dass es sich bei der DownloadAsync
Methode um eine Task
und es sollte gewartet werden:
async Task DownloadAsync ()
{
await Task.Run (() => Download ());
}
void Download ()
{
...
}
Implementieren eines Navigationsmenüs
Das Beispielprogramm, das den gesamten Quellcode in dieser Artikelreihe enthält, verwendet ein ViewModel für seine Startseite. This ViewModel is a definition of a short class with three properties named Type
, , Title
and Description
that contain the type of each of the sample pages, a title, and a short description. Darüber hinaus definiert das ViewModel eine statische Eigenschaft mit dem Namen All
, die eine Auflistung aller Seiten im Programm ist:
public class PageDataViewModel
{
public PageDataViewModel(Type type, string title, string description)
{
Type = type;
Title = title;
Description = description;
}
public Type Type { private set; get; }
public string Title { private set; get; }
public string Description { private set; get; }
static PageDataViewModel()
{
All = new List<PageDataViewModel>
{
// Part 1. Getting Started with XAML
new PageDataViewModel(typeof(HelloXamlPage), "Hello, XAML",
"Display a Label with many properties set"),
new PageDataViewModel(typeof(XamlPlusCodePage), "XAML + Code",
"Interact with a Slider and Button"),
// Part 2. Essential XAML Syntax
new PageDataViewModel(typeof(GridDemoPage), "Grid Demo",
"Explore XAML syntax with the Grid"),
new PageDataViewModel(typeof(AbsoluteDemoPage), "Absolute Demo",
"Explore XAML syntax with AbsoluteLayout"),
// Part 3. XAML Markup Extensions
new PageDataViewModel(typeof(SharedResourcesPage), "Shared Resources",
"Using resource dictionaries to share resources"),
new PageDataViewModel(typeof(StaticConstantsPage), "Static Constants",
"Using the x:Static markup extensions"),
new PageDataViewModel(typeof(RelativeLayoutPage), "Relative Layout",
"Explore XAML markup extensions"),
// Part 4. Data Binding Basics
new PageDataViewModel(typeof(SliderBindingsPage), "Slider Bindings",
"Bind properties of two views on the page"),
new PageDataViewModel(typeof(SliderTransformsPage), "Slider Transforms",
"Use Sliders with reverse bindings"),
new PageDataViewModel(typeof(ListViewDemoPage), "ListView Demo",
"Use a ListView with data bindings"),
// Part 5. From Data Bindings to MVVM
new PageDataViewModel(typeof(OneShotDateTimePage), "One-Shot DateTime",
"Obtain the current DateTime and display it"),
new PageDataViewModel(typeof(ClockPage), "Clock",
"Dynamically display the current time"),
new PageDataViewModel(typeof(HslColorScrollPage), "HSL Color Scroll",
"Use a view model to select HSL colors"),
new PageDataViewModel(typeof(KeypadPage), "Keypad",
"Use a view model for numeric keypad logic")
};
}
public static IList<PageDataViewModel> All { private set; get; }
}
Die XAML-Datei für MainPage
definiert eine ListBox
Eigenschaft, deren ItemsSource
Eigenschaft auf diese All
Eigenschaft festgelegt ist und eine TextCell
für die Anzeige der Title
einzelnen Seiten und Description
Eigenschaften enthält:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.MainPage"
Padding="5, 0"
Title="XAML Samples">
<ListView ItemsSource="{x:Static local:PageDataViewModel.All}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
Die Seiten werden in einer bildlauffähigen Liste angezeigt:
Der Handler in der CodeBehind-Datei wird ausgelöst, wenn der Benutzer ein Element auswählt. Der Handler legt die SelectedItem
Eigenschaft der ListBox
Zurück auf null
und instanziiert dann die ausgewählte Seite und navigiert zu der Seite:
private async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)
{
(sender as ListView).SelectedItem = null;
if (args.SelectedItem != null)
{
PageDataViewModel pageData = args.SelectedItem as PageDataViewModel;
Page page = (Page)Activator.CreateInstance(pageData.Type);
await Navigation.PushAsync(page);
}
}
Video
Xamarin Evolve 2016: MVVM Made Simple with Xamarin.Forms and Prism
Zusammenfassung
XAML ist ein leistungsfähiges Tool zum Definieren von Benutzeroberflächen in Xamarin.Forms Anwendungen, insbesondere, wenn Datenbindung und MVVM verwendet werden. Das Ergebnis ist eine sauber, elegante und potenziell toolierbare Darstellung einer Benutzeroberfläche mit allen Hintergrundunterstützungen im Code.
Verwandte Links
- Teil 1: Erste Schritte mit XAML
- Teil 2: Grundlegende XAML-Syntax
- Teil 3. XAML-Markuperweiterungen
- Teil 4. Grundlagen der Datenbindung
Verwandte Videos
Auf Channel 9 und auf YouTube finden Sie weitere Videos zu Xamarin.