Befehle
Durchsuchen Sie den Beispielcode
In einer .NET Multi-Platform App UI (.NET MAUI)-App, die das Model-View-ViewModel (MVVM)-Muster verwendet, werden Datenbindungen zwischen Eigenschaften im Ansichtsmodell definiert. Dies ist in der Regel eine Klasse, die von INotifyPropertyChanged
abgeleitet ist, und Eigenschaften in der Ansicht, die in der Regel die XAML-Datei ist. Manchmal hat eine App Anforderungen, die über diese Eigenschaftsbindungen hinausgehen, indem der Benutzer Befehle auslösen muss, die etwas im ViewModel beeinflussen. Diese Befehle werden in der Regel ausgeführt, indem Sie auf Schaltflächen klicken oder auf den Bildschirm tippen. Normalerweise werden sie in der CodeBehind-Datei in einem Handler für das Clicked
-Ereignis von Button oder das Tapped
-Ereignis von TapGestureRecognizer verarbeitet.
Über die Befehlsschnittstelle kann jedoch ein alternativer Ansatz für das Implementieren von Befehlen verwendet werden, der für die MVVM-Architektur besser geeignet ist. Das Viewmodel kann Befehle enthalten, d.h. Methoden, die als Reaktion auf eine bestimmte Aktivität in der Ansicht ausgeführt werden, wie etwa einen Button Klick. Datenbindungen werden zwischen diesen Befehlen und Button definiert.
Um eine Datenbindung zwischen einem Button und einem Viewmodel zu ermöglichen, definiert das Button zwei Eigenschaften:
Command
vom TypSystem.Windows.Input.ICommand
CommandParameter
vom TypObject
Um die Befehlsschnittstelle zu verwenden, definieren Sie eine Datenbindung, die auf die Command
Eigenschaft des Button abzielt, wobei die Quelle eine Eigenschaft im Viewmodel vom Typ ICommand ist. Das Viewmodel enthält Code, der mit dieser ICommand Eigenschaft verbunden ist und ausgeführt wird, wenn die Schaltfläche angeklickt wird. Sie können CommandParameter
auf beliebige Daten festlegen, um zwischen mehreren Schaltflächen zu unterscheiden, wenn diese an die gleiche ICommand Eigenschaft im ViewModel gebunden sind.
Viele andere Ansichten definieren Command
und CommandParameter
Eigenschaften. Alle diese Befehle können innerhalb eines ViewModels mit einem Ansatz gehandhabt werden, der nicht vom Benutzeroberflächen-Objekt in der Ansicht abhängt.
ICommands
Die ICommand Schnittstelle ist im System.Windows.Input Namespace definiert und besteht aus zwei Methoden und einem Ereignis:
public interface ICommand
{
public void Execute (Object parameter);
public bool CanExecute (Object parameter);
public event EventHandler CanExecuteChanged;
}
Um die Befehlsschnittstelle zu verwenden, sollte Ihr ViewModel Eigenschaften vom Typ ICommand enthalten:
public ICommand MyCommand { private set; get; }
Die ViewModel-Klasse muss zudem auf eine Klasse verweisen, die die ICommand Schnittstelle implementiert. In der Ansicht ist die Command
Eigenschaft von Button an diese Eigenschaft gebunden:
<Button Text="Execute command"
Command="{Binding MyCommand}" />
Wenn der Benutzer das Button-Element anklickt, ruft Button die Execute
-Methode im ICommand-Objekt auf, das an dessen Command
-Eigenschaft gebunden ist.
Wenn die Bindung zuerst in der Command
-Eigenschaft von Button definiert wird und die Datenbindung sich ändert, ruft Button die CanExecute
-Methode im ICommand-Objekt auf. Wenn CanExecute
false
zurückgibt, deaktiviert Button sich selbst. Das bedeutet, dass der entsprechende Befehl aktuell nicht verfügbar oder ungültig ist.
Button fügt ebenfalls einen Handler an das CanExecuteChanged
-Ereignis von ICommand an. Das Ereignis wird innerhalb des ViewModels ausgelöst. Wenn dieses Ereignis ausgelöst wird, ruft Button erneut CanExecute
auf. Das Button-Element aktiviert sich selbst, wenn CanExecute
true
zurückgibt, und es deaktiviert sich selbst, wenn CanExecute
false
zurückgibt.
Warnung
Verwenden Sie die IsEnabled
-Eigenschaft von Button nicht, wenn Sie die Befehlsschnittstelle verwenden.
Wenn Ihr ViewModel eine Eigenschaft vom Typ ICommand definiert, muss das Viewmodel auch eine Klasse enthalten oder referenzieren, welche die ICommand Schnittstelle implementiert. Diese Klasse muss die Execute
- und CanExecute
-Methoden enthalten oder auf diese verweisen und das CanExecuteChanged
-Ereignis auslösen, wenn die CanExecute
-Methode einen unterschiedlichen Wert zurückgibt. Sie können die Command
oder Command<T>
in .NET MAUI enthaltene Klasse verwenden, um die ICommand Schnittstelle zu implementieren. Durch diese Klassen können Sie den Text der Execute
- und CanExecute
-Methoden in den Konstruktoren der Klassen festlegen.
Tipp
Verwenden Sie Command<T>
, wenn Sie die CommandParameter
Eigenschaft, um zwischen mehreren Ansichten zu unterscheiden, die an die gleiche ICommand Eigenschaft gebunden sind.und die Command
Klasse, wenn dies nicht erforderlich ist.
Grundlegende Befehle
Die folgenden Beispiele veranschaulichen grundlegende Befehle, die in einem Ansichtsmodell implementiert wurden.
Die PersonViewModel
-Klasse definiert drei Eigenschaften namens Name
, Age
und Skills
, über die eine Person definiert wird.
public class PersonViewModel : INotifyPropertyChanged
{
string name;
double age;
string skills;
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
set { SetProperty(ref name, value); }
get { return name; }
}
public double Age
{
set { SetProperty(ref age, value); }
get { return age; }
}
public string Skills
{
set { SetProperty(ref skills, value); }
get { return skills; }
}
public override string ToString()
{
return Name + ", age " + Age;
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Die unten dargestellte PersonCollectionViewModel
Klasse erstellt neue Objekte vom Typ PersonViewModel
und ermöglicht es dem Benutzer, Daten einzugeben. Zu diesem Zweck definiert die Klasse die Eigenschaften IsEditing
vom Typ bool
und PersonEdit
vom Typ PersonViewModel
. Darüber hinaus definiert die Klasse drei Eigenschaften vom Typ ICommand und eine Eigenschaft namens Persons
vom Typ IList<PersonViewModel>
:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
PersonViewModel personEdit;
bool isEditing;
public event PropertyChangedEventHandler PropertyChanged;
···
public bool IsEditing
{
private set { SetProperty(ref isEditing, value); }
get { return isEditing; }
}
public PersonViewModel PersonEdit
{
set { SetProperty(ref personEdit, value); }
get { return personEdit; }
}
public ICommand NewCommand { private set; get; }
public ICommand SubmitCommand { private set; get; }
public ICommand CancelCommand { private set; get; }
public IList<PersonViewModel> Persons { get; } = new ObservableCollection<PersonViewModel>();
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
In diesem Beispiel führen Änderungen an den drei ICommand Eigenschaften und der Persons
Eigenschaft nicht dazu PropertyChanged
,dass Ereignisse ausgelöst werden. Diese Eigenschaften werden allesamt festgelegt, wenn die Klasse erstmalig erstellt wird und ändern sich nicht mehr.
Das folgende Beispiel zeigt die XAML, die PersonCollectionViewModel
verwendet:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.PersonEntryPage"
Title="Person Entry">
<ContentPage.BindingContext>
<local:PersonCollectionViewModel />
</ContentPage.BindingContext>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- New Button -->
<Button Text="New"
Grid.Row="0"
Command="{Binding NewCommand}"
HorizontalOptions="Start" />
<!-- Entry Form -->
<Grid Grid.Row="1"
IsEnabled="{Binding IsEditing}">
<Grid BindingContext="{Binding PersonEdit}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Name: " Grid.Row="0" Grid.Column="0" />
<Entry Text="{Binding Name}"
Grid.Row="0" Grid.Column="1" />
<Label Text="Age: " Grid.Row="1" Grid.Column="0" />
<StackLayout Orientation="Horizontal"
Grid.Row="1" Grid.Column="1">
<Stepper Value="{Binding Age}"
Maximum="100" />
<Label Text="{Binding Age, StringFormat='{0} years old'}"
VerticalOptions="Center" />
</StackLayout>
<Label Text="Skills: " Grid.Row="2" Grid.Column="0" />
<Entry Text="{Binding Skills}"
Grid.Row="2" Grid.Column="1" />
</Grid>
</Grid>
<!-- Submit and Cancel Buttons -->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Submit"
Grid.Column="0"
Command="{Binding SubmitCommand}"
VerticalOptions="Center" />
<Button Text="Cancel"
Grid.Column="1"
Command="{Binding CancelCommand}"
VerticalOptions="Center" />
</Grid>
<!-- List of Persons -->
<ListView Grid.Row="3"
ItemsSource="{Binding Persons}" />
</Grid>
</ContentPage>
In diesem Beispiel wird die BindingContext
Eigenschaft der Seite auf die PersonCollectionViewModel
gesetzt. Das Grid enthält ein Button mit dem Text Neu, dessen Command
Eigenschaft an die NewCommand
Eigenschaft im Viewmodel gebunden ist, ein Eingabeformular mit Eigenschaften, die an die IsEditing
Eigenschaft gebunden sind, sowie Eigenschaften von PersonViewModel
und zwei weitere Schaltflächen, die an die SubmitCommand
und CancelCommand
Eigenschaften des Viewmodel gebunden sind. Die ListView zeigt die Sammlung der bereits eingegebenen Personen an:
Der folgende Screenshot zeigt die aktivierte Schaltfläche Senden nachdem ein Alter festgelegt worden ist:
Wenn der Benutzer erstmalig die Schaltfläche Neu drückt, aktiviert dies das Eingabeformular, deaktiviert aber den Neu Button. Der Benutzer gibt dann einen Namen, ein Alter und seine Qualifikationen ein. Während der Bearbeitung kann der Benutzer jederzeit auf Cancel (Abbrechen) drücken, um von vorne zu beginnen. Die Schaltfläche Submit (Senden) wird nur aktiviert, wenn ein Name und ein gültiges Alter eingegeben wurden. Wenn auf die Schaltfläche Submit (Senden) gedrückt wird, wird die Person an die Collection übertragen, die von ListView angezeigt wird. Nachdem auf Cancel (Abbrechen) oder Submit (Senden) gedrückt wurde, wird das Eingabeformular zurückgesetzt, und die Schaltfläche New (Neu) wird wieder aktiviert.
Die Logik für die Schaltflächen New, Submit und Cancel wird in PersonCollectionViewModel
über die Definitionen der NewCommand
-, SubmitCommand
- und CancelCommand
-Eigenschaften verarbeitet. Der Konstruktor von PersonCollectionViewModel
legt diese drei Eigenschaften auf Objekte vom Typ Command
fest.
Ein Konstruktor der Klasse Command
erlaubt Ihnen die Übergabe von Argumenten des Typs Action
und Func<bool>
, die den Methoden Execute
und CanExecute
entsprechen. Diese Aktion und Funktion können als Lambda-Funktionen im Command
Konstruktor definiert werden:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
NewCommand = new Command(
execute: () =>
{
PersonEdit = new PersonViewModel();
PersonEdit.PropertyChanged += OnPersonEditPropertyChanged;
IsEditing = true;
RefreshCanExecutes();
},
canExecute: () =>
{
return !IsEditing;
});
···
}
void OnPersonEditPropertyChanged(object sender, PropertyChangedEventArgs args)
{
(SubmitCommand as Command).ChangeCanExecute();
}
void RefreshCanExecutes()
{
(NewCommand as Command).ChangeCanExecute();
(SubmitCommand as Command).ChangeCanExecute();
(CancelCommand as Command).ChangeCanExecute();
}
···
}
Wenn der Benutzer auf die Schaltfläche New klickt, wird die execute
-Funktion ausgeführt, die an den Command
-Konstruktor übergeben wurde. Dadurch wird ein neues PersonViewModel
-Objekt erstellt, ein Handler für das PropertyChanged
-Ereignis des Objekts festgelegt, IsEditing
wird auf true
festgelegt, und die RefreshCanExecutes
-Methode wird aufgerufen, die nach dem Konstruktor definiert wurde.
Die Command
-Klasse implementiert nicht nur die ICommand-Schnittstelle, sondern definiert auch eine Methode namens ChangeCanExecute
. Ein ViewModel sollte ChangeCanExecute
für eine ICommand Eigenschaft immer dann aufrufen, wenn etwas passiert, das den Rückgabewert der CanExecute
Methode ändern könnte. Durch einen Aufruf von ChangeCanExecute
löst die Command
-Klasse die CanExecuteChanged
-Methode aus. An das Button-Element ist ein Handler für dieses Ereignis angefügt, und das Element reagiert, indem CanExecute
erneut aufgerufen wird. Anschließend aktiviert es sich je nach Rückgabewert der Methode selbst.
Wenn die execute
-Methode von NewCommand
RefreshCanExecutes
aufruft, erhält die NewCommand
-Eigenschaft einen Aufruf von ChangeCanExecute
, und Button ruft die canExecute
-Methode auf, die nun false
zurückgibt, da die IsEditing
-Eigenschaft nun den Wert true
aufweist.
Der PropertyChanged
Handler für das neue PersonViewModel
Objekt ruft die ChangeCanExecute
Methode von SubmitCommand
auf:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
···
SubmitCommand = new Command(
execute: () =>
{
Persons.Add(PersonEdit);
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return PersonEdit != null &&
PersonEdit.Name != null &&
PersonEdit.Name.Length > 1 &&
PersonEdit.Age > 0;
});
···
}
···
}
Die canExecute
-Funktion für SubmitCommand
wird immer dann aufgerufen, wenn sich eine Eigenschaft in dem PersonViewModel
-Objekt ändert, das bearbeitet wird. true
wird nur zurückgegeben, wenn die Name
-Eigenschaft mindestens ein Zeichen lang und Age
größer als 0 ist. In diesem Fall wird die Schaltfläche Submit (Senden) aktiviert.
Die execute
Funktion für Senden entfernt den Handler für geänderte Eigenschaften aus dem PersonViewModel
, fügt das Objekt der Persons
Sammlung hinzu und setzt alles in den Ausgangszustand zurück.
Die execute
-Funktion für die Schaltfläche Cancel (Abbrechen) funktioniert wie die Schaltfläche Submit (Senden), das Objekt wird allerdings nicht zur Sammlung hinzugefügt:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
···
CancelCommand = new Command(
execute: () =>
{
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return IsEditing;
});
}
···
}
Die canExecute
-Methode gibt true
immer dann zurück, wenn PersonViewModel
bearbeitet wird.
Hinweis
Es ist nicht erforderlich, die execute
- und canExecute
-Methoden als Lambdafunktionen zu definieren. Sie können sie als private Methoden in das ViewModel schreiben und sie in den Command
Konstruktoren referenzieren. Dieser Ansatz führt jedoch häufig dazu, dass viele Methoden in ViewModel vorhanden sind, auf die nur einmal verwiesen wird.
Verwendung von Befehlsparametern
Manchmal ist es praktisch, wenn eine oder mehrere Schaltflächen oder andere Objekte der Benutzeroberfläche die gleiche ICommand Eigenschaft im ViewModel gemeinsam nutzen. In diesem Fall verwenden Sie die CommandParameter
Eigenschaft, um zwischen diesen Schaltflächen zu unterscheiden.
Sie können weiterhin die Command
-Klasse für diese freigegebenen ICommand-Eigenschaften verwenden. Die Klasse definiert einen alternativen Konstruktor, der execute
und canExecute
Methoden mit Parametern vom Typ Object
akzeptiert. Auf diese Weise wird CommandParameter
an diese Methoden übergeben. Bei der Angabe eines CommandParameter
ist es jedoch am einfachsten, die generische Klasse Command<T>
zu verwenden, um den Objekttyp auf CommandParameter
zu setzen. Die von Ihnen angegebenen execute
- und canExecute
-Methoden enthalten Parameter dieses Typs.
Im folgenden Beispiel wird eine Tastatur zum Eingeben von Dezimalzahlen veranschaulicht:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.DecimalKeypadPage"
Title="Decimal Keyboard">
<ContentPage.BindingContext>
<local:DecimalKeypadViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="32" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ContentPage.Resources>
<Grid WidthRequest="240"
HeightRequest="480"
ColumnDefinitions="80, 80, 80"
RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto"
ColumnSpacing="2"
RowSpacing="2"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label Text="{Binding Entry}"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Margin="0,0,10,0"
FontSize="32"
LineBreakMode="HeadTruncation"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />
<Button Text="CLEAR"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding ClearCommand}" />
<Button Text="⇦"
Grid.Row="1" Grid.Column="2"
Command="{Binding BackspaceCommand}" />
<Button Text="7"
Grid.Row="2" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="7" />
<Button Text="8"
Grid.Row="2" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="8" />
<Button Text="9"
Grid.Row="2" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="9" />
<Button Text="4"
Grid.Row="3" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="4" />
<Button Text="5"
Grid.Row="3" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="5" />
<Button Text="6"
Grid.Row="3" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="6" />
<Button Text="1"
Grid.Row="4" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="1" />
<Button Text="2"
Grid.Row="4" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="2" />
<Button Text="3"
Grid.Row="4" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="3" />
<Button Text="0"
Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding DigitCommand}"
CommandParameter="0" />
<Button Text="·"
Grid.Row="5" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="." />
</Grid>
</ContentPage>
In diesem Beispiel ist die Seite BindingContext
ein DecimalKeypadViewModel
. Die Entry Eigenschaft dieses ViewModels ist an die Text
Eigenschaft eines Label gebunden. Alle Button Objekte sind an Befehle im ViewModel ClearCommand
, BackspaceCommand
und DigitCommand
gebunden. Die 11 Schaltflächen für die 10 Ziffern und das Dezimaltrennzeichen sind an DigitCommand
gebunden. CommandParameter
unterscheidet zwischen diesen Schaltflächen. Der Wert, der auf CommandParameter
gesetzt wird, ist im Allgemeinen derselbe wie der von der Schaltfläche angezeigte Text, mit Ausnahme des Dezimalpunkts, der aus Gründen der Übersichtlichkeit mit einem mittleren Punktzeichen dargestellt wird:
Die DecimalKeypadViewModel
definiert eine Entry Eigenschaft vom Typ string
und drei Eigenschaften vom Typ ICommand:
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
string entry = "0";
public event PropertyChangedEventHandler PropertyChanged;
···
public string Entry
{
private set
{
if (entry != value)
{
entry = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Entry"));
}
}
get
{
return entry;
}
}
public ICommand ClearCommand { private set; get; }
public ICommand BackspaceCommand { private set; get; }
public ICommand DigitCommand { private set; get; }
}
Die Schaltfläche, die ClearCommand
entspricht, ist immer aktiviert und setzt den Eintrag auf "0" zurück:
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
···
public DecimalKeypadViewModel()
{
ClearCommand = new Command(
execute: () =>
{
Entry = "0";
RefreshCanExecutes();
});
···
}
void RefreshCanExecutes()
{
((Command)BackspaceCommand).ChangeCanExecute();
((Command)DigitCommand).ChangeCanExecute();
}
···
}
Da diese Schaltfläche immer aktiviert ist, ist es nicht notwendig, ein canExecute
-Argument im Command
-Konstruktor anzugeben.
Die RÜCKTASTE wird nur aktiviert, wenn die Länge des Eintrags größer als 1 ist oder wenn Entry nicht der Zeichenfolge „0“ entspricht:
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
···
public DecimalKeypadViewModel()
{
···
BackspaceCommand = new Command(
execute: () =>
{
Entry = Entry.Substring(0, Entry.Length - 1);
if (Entry == "")
{
Entry = "0";
}
RefreshCanExecutes();
},
canExecute: () =>
{
return Entry.Length > 1 || Entry != "0";
});
···
}
···
}
Die Logik für die execute
-Funktion der RÜCKTASTE stellt sicher, dass Entry mindestens die Zeichenfolge „0“ enthält.
Die DigitCommand
-Eigenschaft ist an 11 Schaltflächen gebunden, von denen jede über die CommandParameter
-Eigenschaft identifiziert wird. Der DigitCommand
ist auf eine Instanz der Command<T>
Klasse gesetzt. Bei der Verwendung der Befehlsschnittstelle mit XAML sind die CommandParameter
Eigenschaften in der Regel Zeichenfolgen, die den Typ des generischen Arguments darstellen. Die Funktionen execute
und canExecute
enthalten dann Argumente vom Typ string
:
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
···
public DecimalKeypadViewModel()
{
···
DigitCommand = new Command<string>(
execute: (string arg) =>
{
Entry += arg;
if (Entry.StartsWith("0") && !Entry.StartsWith("0."))
{
Entry = Entry.Substring(1);
}
RefreshCanExecutes();
},
canExecute: (string arg) =>
{
return !(arg == "." && Entry.Contains("."));
});
}
···
}
Die execute
-Methode fügt das Zeichenfolgenargument zur Entry-Eigenschaft hinzu. Wenn das Ergebnis jedoch mit einer Null beginnt (nicht jedoch mit einer Null und einem Dezimaltrennzeichen), muss diese erste Null mithilfe der Substring
-Funktion entfernt werden. Die canExecute
-Methode gibt false
nur zurück, wenn das Argument das Dezimaltrennzeichen ist (d.h. es gibt an, dass das Dezimaltrennzeichen betätigt wird) und Entry bereits ein Dezimaltrennzeichen enthält. Alle execute
-Methoden rufen die RefreshCanExecutes
-Methode auf, die dann ChangeCanExecute
für DigitCommand
und ClearCommand
aufruft. Dadurch wird sichergestellt, dass das Dezimaltrennzeichen und die RÜCKTASTE je nachdem, welche Ziffern eingegeben wurden, aktiviert oder deaktiviert werden.