Teil 5. Von Datenbindungen zu MVVM
Das Architekturmuster Model-View-ViewModel (MVVM) wurde unter Berücksichtigung von XAML erfunden. Das Muster erzwingt eine Trennung zwischen drei Softwareebenen – der XAML-Benutzeroberfläche, die als Ansicht bezeichnet wird; die zugrunde liegenden Daten, als Modell bezeichnet; und ein Vermittler zwischen der Ansicht und dem Modell, das als ViewModel bezeichnet wird. View und ViewModel sind häufig über in der XAML-Datei definierte Datenbindungen verbunden. Der BindingContext für die Ansicht ist in der Regel ein instance des ViewModel.
Ein einfaches ViewModel
Als Einführung in ViewModels sehen wir uns zunächst ein Programm ohne an.
Zuvor haben Sie erfahren, wie Sie eine neue XML-Namespacedeklaration definieren, damit eine XAML-Datei auf Klassen in anderen Assemblys verweisen kann. Im Folgenden sehen Sie 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 von der statischen DateTime.Now
-Eigenschaft abzurufen und diesen DateTime
Wert auf festzulegen, auf StackLayout
:BindingContext
<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>
BindingContext
ist eine besondere Eigenschaft: Wenn Sie die für BindingContext
ein Element festlegen, wird es von allen untergeordneten Elementen dieses Elements geerbt. Dies bedeutet, dass alle untergeordneten Elemente von StackLayout
den gleichen BindingContext
aufweisen und 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, denen anscheinend ein Bindungspfad fehlt. Dies bedeutet, dass der DateTime
Wert selbst für verwendet StringFormat
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 Datum und 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 zu helfen. Wenn Sie im Sinne von MVVM denken, sind Model und ViewModel Klassen, die vollständig im Code geschrieben sind. Die Ansicht ist häufig eine XAML-Datei, die über Datenbindungen auf im ViewModel definierte Eigenschaften verweist.
Ein richtiges Modell ist unwissend gegenüber dem ViewModel, und ein richtiges ViewModel ist unwissend gegenüber der Ansicht. Allerdings passt ein Programmierer häufig die Datentypen an, die vom ViewModel verfügbar gemacht werden, an die Datentypen, die bestimmten Benutzeroberflächen zugeordnet sind. Wenn beispielsweise ein Modell auf eine Datenbank zugreift, die 8-Bit-ASCII-Zeichenfolgen enthält, muss ViewModel zwischen diesen Zeichenfolgen in Unicode-Zeichenfolgen konvertieren, um die ausschließliche Verwendung von Unicode auf der Benutzeroberfläche zu ermöglichen.
In einfachen MVVM-Beispielen (wie die hier gezeigten) gibt es häufig überhaupt kein Modell, und das Muster umfasst nur ein View und ViewModel, das mit Datenbindungen verknüpft ist.
Hier ist ein ViewModel für eine Uhr mit nur einer einzelnen 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 im Allgemeinen die INotifyPropertyChanged
-Schnittstelle. Dies bedeutet, dass die -Klasse jedes Mal ein PropertyChanged
Ereignis auslöst, wenn sich eine ihrer Eigenschaften ändert. Der Datenbindungsmechanismus in Xamarin.Forms fügt einen Handler an dieses PropertyChanged
Ereignis an, sodass es 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, dass auf ClockViewModel
die BindingContext
der Label
verwendenden Eigenschaftselementtags festgelegt ist. Alternativ können Sie die ClockViewModel
in einer Resources
Auflistung instanziieren und über eine StaticResource
Markuperweiterung auf festlegenBindingContext
. Oder die CodeBehind-Datei kann das ViewModel instanziieren.
Die Binding
Markuperweiterung für die Text
-Eigenschaft der 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}'}" … >
Interaktives MVVM
MVVM wird häufig mit bidirektionalen Datenbindungen für eine interaktive Ansicht verwendet, die auf einem zugrunde liegenden Datenmodell basiert.
Im Folgenden sehen Sie eine Klasse namens HslViewModel
, die einen Color
Wert in Hue
, Saturation
- und Luminosity
-Werte und umgekehrt konvertiert:
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
Eigenschaften , Saturation
und Luminosity
bewirken, dass sich die Color
Eigenschaft ändert, und Änderungen an Color
bewirken, dass sich die anderen drei Eigenschaften ändern. Dies kann wie eine Endlosschleife erscheinen, mit der Ausnahme, dass die -Klasse das PropertyChanged
-Ereignis erst aufruft, wenn sich die Eigenschaft geändert hat. Dadurch wird die ansonsten nicht kontrollierbare Feedbackschleife beendet.
Die folgende XAML-Datei enthält eine BoxView
, deren Color
Eigenschaft an die Color
Eigenschaft des ViewModel gebunden ist, und drei Slider
und drei Label
Ansichten, die an die Hue
Eigenschaften , Saturation
und Luminosity
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 für jedes Label
ist die Standardbindung OneWay
. Es muss nur der Wert angezeigt werden. Die Bindung für jedes Slider
ist TwoWay
jedoch . Dadurch kann die Slider
aus viewModel initialisiert werden. Beachten Sie, dass die Color
-Eigenschaft auf Aqua
festgelegt ist, wenn viewModel instanziiert wird. Eine Änderung in muss Slider
jedoch auch einen neuen Wert für die Eigenschaft im ViewModel festlegen, das dann eine neue Farbe berechnet.
Befehlen mit ViewModels
In vielen Fällen ist das MVVM-Muster auf die Bearbeitung von Datenelementen beschränkt: Benutzeroberflächenobjekte in der Ansicht parallele Datenobjekte in 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 dies das ViewModel an ein bestimmtes Benutzeroberflächenparadigma binden würde.
Damit ViewModels unabhängiger von bestimmten Benutzeroberflächenobjekten sein kann, aber trotzdem Methoden innerhalb des ViewModel aufgerufen werden können, ist eine Befehlsschnittstelle vorhanden. Diese Befehlsschnittstelle wird von den folgenden Elementen in Xamarin.Formsunterstützt:
Button
MenuItem
ToolbarItem
SearchBar
TextCell
(und damit auchImageCell
)ListView
TapGestureRecognizer
Mit Ausnahme des SearchBar
- und ListView
-Elements definieren diese Elemente zwei Eigenschaften:
Command
vom TypSystem.Windows.Input.ICommand
CommandParameter
vom TypObject
Definiert SearchBar
SearchCommand
die Eigenschaften undSearchCommandParameter
, während eine ListView
Eigenschaft vom Typ ICommand
definiert RefreshCommand
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 des Typs ICommand
definieren. Sie können diese Eigenschaften dann an die Command
-Eigenschaft jedes Button
oder eines anderen Elements oder vielleicht an eine benutzerdefinierte Ansicht binden, die diese Schnittstelle implementiert. Optional können Sie die CommandParameter
-Eigenschaft festlegen, um einzelne Button
Objekte (oder andere Elemente) zu identifizieren, die an diese ViewModel-Eigenschaft gebunden sind. Intern ruft die Button
- Execute
Methode auf, wenn der Benutzer auf tippt, Button
und an die Execute
-Methode CommandParameter
übergeben.
Die CanExecute
Methode und CanExecuteChanged
das Ereignis werden für Fälle verwendet, in denen ein Button
Tippen derzeit ungültig sein kann. In diesem Fall sollte sich das Button
selbst deaktivieren. Der Button
ruft auf CanExecute
, wenn die Command
-Eigenschaft zum ersten Mal festgelegt wird und wann immer das CanExecuteChanged
Ereignis ausgelöst wird. Wenn CanExecute
zurückgibt false
, deaktiviert sich der Button
selbst und generiert Execute
keine Aufrufe.
Um Hilfe beim Hinzufügen von Befehlen zu Ihren ViewModels zu benötigen, definiert zwei Klassen, Xamarin.Forms die implementieren ICommand
: Command
und Command<T>
wobei T
der Typ der Argumente für Execute
und CanExecute
ist. Diese beiden Klassen definieren mehrere Konstruktoren sowie eine ChangeCanExecute
Methode, die viewModel aufrufen kann, um das Auslösen des Ereignisses durch das Command
Objekt zu erzwingen CanExecuteChanged
.
Hier ist ein ViewModel für eine einfache Tastatur, die zum Eingeben von Telefonnummern vorgesehen ist. Beachten Sie, dass die - und CanExecute
-Execute
Methode direkt im Konstruktor als Lambdafunktionen 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 AddCharCommand
Eigenschaft an die Command
-Eigenschaft mehrerer Schaltflächen gebunden ist (oder an ein anderes Element, das über eine Befehlsschnittstelle verfügt), von denen jede durch CommandParameter
identifiziert wird. Diese Schaltflächen fügen einer InputString
Eigenschaft Zeichen hinzu, die dann als Telefonnummer für die DisplayText
Eigenschaft formatiert wird.
Es gibt auch eine zweite Eigenschaft vom Typ ICommand
namens DeleteCharCommand
. Dies ist an eine Rückabstandsschaltfläche gebunden, aber die Schaltfläche sollte deaktiviert werden, wenn keine Zeichen zum Löschen vorhanden sind.
Die folgende Tastatur ist visuell nicht so anspruchsvoll, wie sie 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 der ersten Button
, die in diesem Markup angezeigt wird, ist an das DeleteCharCommand
gebunden. Der Rest ist an das AddCharCommand
mit einem CommandParameter
gebunden, das dem Zeichen entspricht, das auf dem Button
Gesicht angezeigt wird. Hier ist das Programm in Aktion:
Aufrufen asynchroner Methoden
Befehle können auch asynchrone Methoden aufrufen. Dies wird erreicht, indem beim Angeben Execute
der -Methode die async
Schlüsselwörter und await
verwendet werden:
DownloadCommand = new Command (async () => await DownloadAsync ());
Dies gibt an, dass die DownloadAsync
-Methode eine Task
ist und erwartet werden sollte:
async Task DownloadAsync ()
{
await Task.Run (() => Download ());
}
void Download ()
{
...
}
Implementieren eines Navigationsmenüs
Das XamlSamples-Programm , das den gesamten Quellcode in dieser Artikelreihe enthält, verwendet ein ViewModel für seine Startseite. Dieses ViewModel ist eine Definition einer kurzen Klasse mit drei Eigenschaften mit dem Namen Type
, Title
und Description
die den Typ der einzelnen Beispielseiten, einen Titel und eine kurze Beschreibung enthalten. Darüber hinaus definiert ViewModel eine statische Eigenschaft namens 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
, deren ItemsSource
Eigenschaft auf diese All
Eigenschaft festgelegt ist und die eine TextCell
zum Anzeigen der Title
Eigenschaften und Description
jeder Seite 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 scrollbaren Liste angezeigt:
Der Handler in der CodeBehind-Datei wird ausgelöst, wenn der Benutzer ein Element auswählt. Der Handler legt die SelectedItem
-Eigenschaft des ListBox
back auf null
fest, instanziiert dann die ausgewählte Seite und navigiert zu dieser:
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 einfach gemacht mit Xamarin.Forms und Prism
Zusammenfassung
XAML ist ein leistungsstarkes 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 werkzeugfähige Darstellung einer Benutzeroberfläche mit der gesamten Hintergrundunterstützung im Code.
Ähnliche Themen
- XamlSamples
- 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.