DelegateCommand-Klasse
Vereinfacht Commands für ViewModels nach dem MVVM-Muster. Stellt eine ICommand-Implementierung bereit, die die Execute- und CanExecute-Methoden an Delegaten weiterleitet.
Das Problem
Neben der Datenbindung zwischen der View- und der ViewModel-Ebene im MVVM-Muster, die eher andauernde Zustände darstellt, müssen von der View aus auch Aktionen im ViewModel ausgelöst werden, also Ereignisse, die zu einem Zeitpunkt auftreten. Das .NET-Framework stellt für diesen Zweck die ICommand
-Schnittstelle bereit, die einen Befehl ausführt und darüber Auskunft gibt, ob er gerade ausgeführt werden kann.
Um diese Schnittstelle zu bedienen, müsste für jedes Command eine separate Klasse erstellt werden, die nur die Logik dieses einen Befehls enthält. In umfangreichen Oberflächen sind das sehr viele Klassen, manche mit nur wenigen Zeilen Code. Außerdem können diese Klassen nicht auf den internen Zustand des ViewModels zugreifen, den sie doch meist verändern sollen.
Die Lösung
Um das zu vereinfachen, gibt es die DelegateCommand
-Klasse, manchmal auch RelayCommand
genannt. Diese Klasse implementiert die ICommand
-Schnittstelle, enthält aber nicht selbst die Befehlslogik, sondern nur einen Delegaten, der sie ausführt. Dieser Delegat, eine Methode, wird im Konstruktor von DelegateCommand
angegeben. Die Methode befindet sich dabei i. d. R. in derselben ViewModel-Klasse, die auch das Command bereitstellt. Viele kurze Methoden befinden sich somit auch gleich in der Klasse, mit der sie arbeiten sollen, z. B. deren Eigenschaften sie verändern, die dann wiederum per Datenbindung auf der Oberfläche angezeigt werden.
Neben Delegaten für die beiden Methoden Execute
und CanExecute
mit jeweils einem object
-Parameter gibt es in dieser Klasse auch Überladungen, die keinen Parameter annehmen, und weitere Hilfsmethoden. TryExecute
z. B. ruft nur dann Execute
auf, wenn CanExecute
true zurückgibt. Alternativ zum Aufruf der CanExecute
-Methode lässt sich auch die Eigenschaft IsEnabled
setzen. Die RaiseCanExecuteChanged
-Methode löst das gleichnamige Ereignis aus, mit dem die Verfügbarkeit des Commands neu abgefragt wird; RaiseCanExecuteChangedAsync
verzögert das Ereignis. Die statische Eigenschaft DelegateCommand.
stellt ein Command bereit, das generell nicht verfügbar ist und nichts tut.
Kompatibilität:
Beispiel
Die folgende Beispielklasse zeigt ein ViewModel mit Commands:
{
// Deklaration aller Commands für dieses ViewModel als öffentliche Eigenschaften
public DelegateCommand OpenFileCommand { get; private set; }
public DelegateCommand SaveCommand { get; private set; }
public DelegateCommand SaveAsCommand { get; private set; }
public DelegateCommand PrintCommand { get; private set; }
public DelegateCommand QuitCommand { get; private set; }
// Konstruktor
public MainViewModel()
{
// Initialisierung der Commands, jeweils mit Handler-Methode und optional
// einer Implementierung für CanExecute
OpenFileCommand = new DelegateCommand(OnOpenFile);
SaveCommand = new DelegateCommand(OnSave, CanSave);
SaveAsCommand = new DelegateCommand(OnSaveAs, CanSave);
// Drucken wird noch nicht unterstützt, soll also immer deaktiviert sein
PrintCommand = DelegateCommand.Disabled;
QuitCommand = new DelegateCommand(OnQuit);
}
// Methode, die aufgerufen wird, wenn eine Datei geladen werden soll
private void OnOpenFile()
{
LoadedFile = AskForFile();
// Die Speichern-Befehle stehen jetzt zur Verfügung, ihre Ausführbarkeit
// soll jetzt neu abgefragt werden, um UI-Elemente zu aktivieren
SaveCommand.RaiseCanExecuteChanged();
SaveAsCommand.RaiseCanExecuteChanged();
// Statt eine CanExecute-Methode zu implementieren, kann ein Befehl auch
// per Eigenschaft aktiviert und deaktiviert werden
QuitCommand.IsEnabled = false;
}
// Methode, die ermittelt, ob gespeichert werden kann. Wird hier für beide
// Speichern-Befehle gleichermaßen verwendet.
private bool CanSave()
{
// Speichern geht, wenn eine Datei geladen wurde
return LoadedFile != null;
}
private void OnSave()
{
WriteFile(LoadedFile);
}
private void OnSaveAs()
{
LoadedFile.FileName = newFileName;
// Der Speichern-Befehl wird hier wiederverwendet und ausgeführt,
// wenn er gerade ausführbar ist. Sonst passiert nichts.
SaveCommand.TryExecute();
}
private void OnQuit()
{
if (LoadedFile.IsModified)
{
AskUserToSave();
}
else
{
CloseApplication();
}
}
}
Download
DelegateCommand.cs10,3 KiBQuelltext der DelegateCommand-Klasse
Lizenz und Nutzungsbedingungen
Vervielfältigung und Weiterverbreitung dieser Datei, verändert oder unverändert, sind gestattet, vorausgesetzt die Urheberrechtsangabe und dieser Hinweis bleiben erhalten. Diese Datei wird wie vorliegend ohne jegliche Garantie oder Gewährleistung angeboten. (GNU All-Permissive-Lizenz)
Statistische Daten
- Erstellt am 2012-07-09, aktualisiert am 2016-08-28.
- Ca. 170 Codezeilen, geschätzte Entwicklungskosten: 170 - 680 €