This article has been localized into German by the community.
Verwendung von WPF Befehlen
Im vorherigen Artikel befassten wir uns viel mit der Theorie von Befehlen und wie sie funktionieren. In diesem Kapitel schauen wir uns an, wie sie eigentlich benutzt werden, indem sie zu Benutzeroberflächen zugewiesen und Befehlsbindungen erstellt werden können, die alles miteinander verlinken.
Wir fangen mit einem sehr einfachen Beispiel an:
<Window x:Class="WpfTutorialSamples.Commands.UsingCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UsingCommandsSample" Height="100" Width="200">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute" />
</Window.CommandBindings>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Command="ApplicationCommands.New">New</Button>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Commands
{
public partial class UsingCommandsSample : Window
{
public UsingCommandsSample()
{
InitializeComponent();
}
private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The New command was invoked");
}
}
}
Wir definieren ein Command Binding auf dem Fenster, indem wir es zu seiner CommandBindings Collection hinzufügen. Wir spezifizieren welches Command wir nutzen möchten (den neuen Command von den ApplicationCommands), sowie zwei Event Handler. Die visuelle Schnittstelle besteht aus einem einzigen Button, den wir mit dem Command Property dem Command zuweisen
Im Code-behind behandeln wir die beiden Ereignisse. Der CanExecute-Handler, den WPF aufruft, wenn die Anwendung im Leerlauf ist, um zu sehen, ob der spezifische Befehl aktuell verfügbar ist, ist für dieses Beispiel sehr einfach, da wir wollen, dass dieser spezielle Befehl immer verfügbar ist. Dies geschieht, indem die CanExecute-Eigenschaft der Ereignisargumente auf true gesetzt wird.
Der Executed Handler zeigt einfach eine Meldung an, wenn der Befehl aufgerufen wird. Wenn Sie das Beispielprojekt ausführen und die Taste drücken, wird diese Meldung angezeigt. Zu beachten ist, dass dieser Befehl schon ein Standardtastaturkürzel definiert hat, das Sie als zusätzlichen Vorteil erhalten. Anstatt auf die Schaltfläche zu klicken, können Sie Strg+N auf Ihrer Tastatur drücken - das Ergebnis ist dasselbe.
Verwendung der CanExecute-Methode
Im ersten Beispiel haben wir ein CanExecute-Ereignis implementiert, das einfach true zurückgibt, so dass der Befehl immer verfügbar ist. Dies gilt natürlich nicht für alle Befehle - in vielen Fällen soll der Befehl je nach Zustand in Ihrer Anwendung aktiviert oder deaktiviert sein.
Ein sehr häufiges Beispiel dafür ist das Umschalten von Buttons für die Verwendung der Windows-Zwischenablage, wobei die Buttons "Ausschneiden" und "Kopieren" nur aktiviert werden sollen, wenn Text ausgewählt ist, und die Schaltfläche "Einfügen" nur aktiviert werden soll, wenn Text in der Zwischenablage vorhanden ist. Das ist genau das, was wir in diesem Beispiel erreichen werden:
<Window x:Class="WpfTutorialSamples.Commands.CommandCanExecuteSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandCanExecuteSample" Height="200" Width="250">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Cut" CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
<CommandBinding Command="ApplicationCommands.Paste" CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" Width="60">_Cut</Button>
<Button Command="ApplicationCommands.Paste" Width="60" Margin="3,0">_Paste</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Commands
{
public partial class CommandCanExecuteSample : Window
{
public CommandCanExecuteSample()
{
InitializeComponent();
}
private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = (txtEditor != null) && (txtEditor.SelectionLength > 0);
}
private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Cut();
}
private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = Clipboard.ContainsText();
}
private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Paste();
}
}
}
Hier haben wir diese sehr einfache Schnittstelle mit ein paar Buttons und einem TextBox-Control. Der erste Button schneidet in die Zwischenablage ("Cut") und der zweite Button fügt daraus ein ("Paste").
In Code-behind haben wir zwei Ereignisse für jeden Button: Eines, das die eigentliche Aktion ausführt, deren Name mit _Executed endet, und dann die CanExecute-Ereignisse. In jedem von ihnen werden Sie sehen, dass ich eine Logik anwende, um zu entscheiden, ob die Aktion ausgeführt werden kann oder nicht, und sie dann dem Rückgabewert CanExecute auf den EventArgs zuweisen.
Das Coole daran ist, dass Sie diese Methoden nicht aufrufen müssen, um Ihre Schaltflächen aktualisieren zu lassen - WPF macht das automatisch, wenn die Anwendung im Leerlauf ist, und stellt sicher, dass Ihre Schnittstelle ständig aktualisiert bleibt.
Standardverhalten von Befehlen und CommandTarget
Wie wir im vorhergehenden Beispiel gesehen haben, kann die Handhabung mehrerer Befehle zu einer Menge Code führen, mit vielen Methodendeklarationen und immer wiederkehrender Logik. Das ist wahrscheinlich der Grund, warum das WPF-Team beschlossen hat, einige davon für Sie zu erledigen. Tatsächlich hätten wir im vorherigen Beispiel alle Code-behind vermeiden können, da eine WPF TextBox automatisch gängige Befehle wie Cut, Copy, Paste, Undo und Redo verarbeiten kann.
WPF tut dies, indem es die Ereignisse Executed und CanExecute für Sie behandelt, wenn ein Texteingabe-Control wie die TextBox den Fokus hat. Es steht Ihnen frei, diese Ereignisse zu überschreiben, was wir im vorherigen Beispiel getan haben. Aber wenn Sie nur das Standardverhalten wollen, können Sie WPF anweisen, die Befehle und das TextBox-Steuerelement zu verbinden und die Arbeit für Sie zu erledigen. Sehen Sie nur, wie viel einfacher dieses Beispiel ist:
<Window x:Class="WpfTutorialSamples.Commands.CommandsWithCommandTargetSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandsWithCommandTargetSample" Height="200" Width="250">
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" CommandTarget="{Binding ElementName=txtEditor}" Width="60">_Cut</Button>
<Button Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=txtEditor}" Width="60" Margin="3,0">_Paste</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
Für dieses Beispiel wird kein Code-behind-Code benötigt - WPF erledigt das alles für uns, aber nur, weil wir diese spezifischen Befehle für dieses spezifische Steuerelement verwenden wollen. Die TextBox erledigt die Arbeit für uns.
Beachten Sie, wie ich die CommandTarget-Eigenschaften auf den Schaltflächen verwende, um die Befehle an unser TextBox-Steuerelement zu binden. Dies ist in diesem speziellen Beispiel erforderlich, da das WrapPanel die Fokussierung nicht so handhabt, wie z.B. eine Symbolleiste oder ein Menü, aber es ist auch sehr sinnvoll, den Befehlen ein Ziel zu geben.
Zusammenfassung
Der Umgang mit Befehlen ist ziemlich einfach, beinhaltet aber etwas mehr Markup und Code. Die Belohnung ist besonders offensichtlich, wenn Sie die gleiche Aktion von mehreren Stellen aus aufrufen müssen, oder wenn Sie eingebaute Befehle verwenden, die WPF vollständig für Sie handhaben kann, wie wir im letzten Beispiel gesehen haben.