Commands verwenden

Wenn Sie unter Access und VBA Ereignisse programmiert haben, hat beispielsweise jedes Steuer-element, jede Ribbon-Schaltfläche und jeder Kontextmenü-Eintrag ein eigenes Ereignis erhalten – auch, wenn diese genau die gleiche Funktion auslösen sollten. Das war schon durch die unterschiedlichen Schnittstellen nötig. Unter WPF können Sie ein und dieselbe Funktion von verschiedenen Steuerelementen aus auslösen. Das gelingt allerdings nicht mit herkömmlichen Ereignismethoden, sondern mit sogenannten Commands. Was das ist und wie Sie es in Ihre Anwendungen einbauen können, zeigt der vorliegende Artikel.

Vorteil: Alles an einem Ort

Neben der Möglichkeit, benutzerdefinierte Ereignisse durch Commands abzubilden und diese von überall in der Anwendung aufzurufen, bieten Commands noch weitere Möglichkeiten: So gibt es auch eingebaute Commands, die etwa Basisfunktionalitäten der Zwischenablage wie Kopieren, Ausschneiden oder Einfügen bereitstellen. Wenn Sie einmal mit Access programmiert haben, wissen Sie, dass diese Funktionen immer in Form von API-Funktionen selbst bereitgestellt werden mussten und Sie nicht einfach die Systemfunktionen nutzen konnten. Diese würden Sie dann von jedem Ort, wo diese Funktion benötigt wird, aufrufen müssen, und zwar von der dafür vorgesehenen Ereignisporzedur aus. Wir schauen uns also in diesem Artikel zwei verschiedene Typen von Commands an: benutzerdefinierte und eingebaute Commands.

Vorteil: Tastenkombinationen

Ein weiterer Vorteil von Commands ist, dass Sie für ein benutzerdefiniertes Command eine Tastenkombination definieren können beziehungsweise, dass die Tastenkombinationen für eingebaute Commands bereits vorhanden sind – wie beispielsweise Strg + C, Strg + X oder Strg + V für Kopieren, Ausschneiden und Einfügen.

Vorteil: Aktivieren und Deaktivieren

Commands wie die zum Kopieren, Ausschneiden oder Einfügen des aktuell markierten Inhalts werden automatisch aktiviert oder deaktiviert – je nachdem, ob gerade ein Inhalt zum Kopieren oder Ausschneiden markiert beziehungsweise ob die Zwischenablage überhaupt Inhalt enthält, der aktuell eingefügt werden kann (siehe Bild 1). Auch für benutzerdefinierte Commands können Sie an einer Stelle festlegen, ob und wann diese aktiviert oder deaktiviert sind – abhängig vom jeweiligen Kontext. Während das für die Funktionen der Zwischenablage automatisch funktioniert, schauen wir uns später auch an, wie Sie benutzerdefinierte Commands von einer Stelle aus aktivieren und deaktivieren.

Aktivierte und deaktivierte Kontextmenü-Einträge

Bild 1: Aktivierte und deaktivierte Kontextmenü-Einträge

Definition von Commands

Wenn Sie ein Command definieren, erledigen Sie das unter Verwendung der ICommand-Schnittstelle. Diese sieht vor, dass Sie die folgenden beiden Methoden implementieren:

  • Execute: Enthält die Anweisungen, die beim Aufruf des Commands ausgeführt werden sollen.
  • CanExecute: Enthält Code, der festlegt, ob das Command gerade aktiviert oder deaktiviert ist.

Commands aufrufen

Um ein solches Command aufzurufen, müssen Sie für das jeweilige Steuer-element über ein sogenanntes Command binding festlegen, welches Command für das jeweilige Ereignis aufgerufen werden soll. Für eingebaute Commands ist dies einfacher als für benutzerdefinierte Commands. Wir schauen uns das für ein eingebautes Command an einem einfachen Beispiel an.

Dabei wollen wir die drei Befehle zum Ausschneiden, Kopieren und Einfügen in drei Schaltflächen unterbringen und mit diesen den Inhalt eines Textfeldes bearbeiten können. Der WPF-Code dafür sieht wie folgt aus:

<StackPanel Orientation="Horizontal">
     <Button x:Name="cmdAusschneiden" Command="ApplicationCommands.Cut">Ausschneiden</Button>
     <Button x:Name="cmdKopieren" Command="ApplicationCommands.Copy">Kopieren</Button>
     <Button x:Name="cmdEinfuegen" Command="ApplicationCommands.Paste">Einfügen</Button>
</StackPanel>
<TextBox x:Name="txtText" Grid.Row="1" Width="200"/>

Wir haben hier herkömmliche Schaltflächen angelegt, für die wir allerdings nicht das Click-Ereignis definiert haben, sondern mit dem Command-Attribut ein Command definiert haben, das beim Anklicken der Schaltfläche ausgelöst werden soll.

Das Ergebnis sieht wie in Bild 2 aus. Leider werden die Schaltflächen nicht aktiviert oder deaktiviert, wenn man einen Teil des Textes im Textfeld markiert. Dazu fehlt freilich noch ein Attribut – wir haben nämlich noch nicht festgelegt, auf welches Element der Benutzeroberfläche sich die Commands beziehen sollen. Das legen wir mit dem Attribut CommandTarget fest, welches per Binding das entsprechende Steuer-element referenziert:

Schaltflächen, die nicht aktiviert werden

Bild 2: Schaltflächen, die nicht aktiviert werden

<Button x:Name="cmdAusschneiden" Command="ApplicationCommands.Cut"     CommandTarget="{Binding ElementName=txtText}">Ausschneiden</Button>
<Button x:Name="cmdKopieren" Command="ApplicationCommands.Copy"     CommandTarget="{Binding ElementName=txtText}">Kopieren</Button>
<Button x:Name="cmdEinfuegen" Command="ApplicationCommands.Paste"     CommandTarget="{Binding ElementName=txtText}">Einfügen</Button>

Wenn das Textfeld leer ist, die Zwischenablage jedoch einen Wert enthält, der in das Textfeld eingefügt werden kann, wird nur die Einfügen-Schaltfläche aktiviert – und sie fügt den Inhalt der Zwischenablage auch per Mausklick ein (siehe Bild 3). Wenn sich beispielsweise ein Objekt wie eine Datei in der Zwischenablage befindet, wird die Einfügen-Schaltfläche nicht aktiviert, denn ein solches Objekt kann nicht in das Textfeld eingefügt werden. Gleiches gilt, wenn die Zwischenablage komplett leer ist.

Aktivierte Einfügen-Schaltfläche

Bild 3: Aktivierte Einfügen-Schaltfläche

Hat der Benutzer zusätzlich noch mindestens ein Zeichen im Textfeld txtText markiert, werden auch die beiden Schaltflächen zum Ausschneiden und Kopieren aktiviert (siehe Bild 4). Und auch das Ausschneiden und Kopieren mit den Schaltflächen funktioniert ohne Probleme.

Durch Markierung aktivierte Ausschneiden- und Einfügen-Schaltflächen

Bild 4: Durch Markierung aktivierte Ausschneiden- und Einfügen-Schaltflächen

Hier geschehen also einige Dinge automatisch – sowohl die Aktionen, die durch die Schaltflächen ausgeführt werden sollen, werden durch die Zuweisung des entsprechenden Wertes zum Attribut Command automatisch ausgeführt als auch die Aktivierung oder Deaktivierung abhängig vom Status des mit CommandTarget angegebenen Steuerelements.

Commands mit IntelliSense

Weiter oben haben wir einfach das Command als Wert der Command-Eigenschaft angegeben. Wenn Sie das auch gemacht haben, ist Ihnen vielleicht aufgefallen, dass es hier keine IntelliSense-Unterstützung gab, was für Visual Studio eher ungewöhnlich ist. Mit einer etwas anderen Schreibweise gelangen Sie allerdings schnell zur Anzeige der möglichen Befehle per IntelliSense. Diese sieht wie folgt aus – hier am Beispiel der Ausschneiden-Schaltfläche:

<Button x:Name="cmdAusschneiden" Command="{x:Static ApplicationCommands.Cut}"     CommandTarget="{Binding ElementName=txtText}">Ausschneiden</Button>

Eingebaute Commands überschreiben

Wenn Sie schon eingebaute Commands nutzen können, um von verschiedenen Steuerelementen darauf zugreifen zu können, dann wäre es doch praktisch, wenn man diese eingebauten Commands auch überschreiben könnte. Damit meinen wir beispielsweise, dass Sie die Ausschneiden-Aktion ApplicationCommands.Cut durch eine eigene Methode ersetzen, die vor dem Ausschneiden noch nachfragt, ob der Inhalt wirklich ausgeschnitten werden soll.

Dazu können Sie mit dem Executed-Attribut eine statt der eigentlichen Funktion einzusetzende Methode angeben und diese dann im Code behind-Modul des WPF-Fensters implementieren. Dazu fügen wir in der XAML-Datei ein Element namens TextBox.CommandBindings mit dem Unterelement CommandBinding hinzu, das die drei Attribute Command, CanExecute und Executed enthält – und zwar für das Textfeld, für das wir das Command anpassen wollen:

<TextBox x:Name="txtText" Grid.Row="1" Width="200">
     <TextBox.CommandBindings>
         <CommandBinding Command="{x:Static ApplicationCommands.Cut}" CanExecute="CommandBinding_CanExecute"             Executed="CommandBinding_Executed" />
     </TextBox.CommandBindings>
</TextBox>

Hier tragen wir ein, dass es sich um das Command-Element ApplicationCommands.Cut handelt und wie die auszuführenden Methoden für CanExecute und Executed heißen.

Den Rest der Definition für die Schaltfläche cmdAusschneiden behalten wir bei:

<Grid>
     <StackPanel Orientation="Horizontal">
             <Button x:Name="cmdAusschneiden" Command="{x:Static ApplicationCommands.Cut}"                 CommandTarget="{Binding ElementName=txtText}" Content="Ausschneiden" >
             </Button>
         ...
</Grid>

In der Code behind-Klasse fügen wir die beiden für die Attribute CanExecute und Executed angegebenen Methoden hinzu. Um das möglichst einfach zu gestalten, erledigen wir das wie folgt:

  • Tippen Sie den Namen des Attributs ein, also beispielsweise Executed.
  • Geben Sie das Gleichheitszeichen ein. Es erscheint ein Popup mit zwei Befehlen, von denen Sie den ersten namens wählen.
  • Das legt automatisch die Ereignismethode mit den passenden Parametern in der Code behind-Datei an.

Die Code behind-Klasse sieht nach dem Anlegen der beiden Ereignismethoden CommandBinding_CanExecute und CommandBinding_Executed wie folgt aus:

Class MainWindow
     Private Sub CommandBinding_CanExecute(sender As Object, e As CanExecuteRoutedEventArgs)
         e.CanExecute = True
     End Sub
     Private Sub CommandBinding_Executed(sender As Object, e As ExecutedRoutedEventArgs)
         MessageBox.Show("Überschriebenes Ausschneiden-Command")
     End Sub
End Class

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins DATENBANKENTWICKLER:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar