Beispiel für ein benutzerdefiniertes WPF-Befehlsmuster
-
08-06-2019 - |
Frage
Ich habe ein wenig WPF-Programmierung gemacht und eine Sache, die ich nie verstanden habe, war das Befehlsmuster.Jedes Beispiel scheint für eingebaute Beispiele gedacht zu sein: Bearbeiten, Ausschneiden, Einfügen.Hat jemand ein Beispiel oder einen Vorschlag für Best Practices für benutzerdefinierte Befehle?
Lösung
Ah ha!Eine Frage, die ich beantworten kann!Zunächst sollte ich erwähnen, dass es für mich persönlich einfacher ist, Befehle im Code zu definieren und einzubinden als in XAML.Dadurch kann ich die Handler für die Befehle etwas flexibler einbinden als bei einem reinen XAML-Ansatz.
Sie sollten herausfinden, welche Befehle Sie haben möchten und worauf sie sich beziehen.In meiner Anwendung habe ich derzeit eine Klasse zum Definieren wichtiger Anwendungsbefehle wie folgt:
public static class CommandBank
{
/// Command definition for Closing a window
public static RoutedUICommand CloseWindow { get; private set; }
/// Static private constructor, sets up all application wide commands.
static CommandBank()
{
CloseWindow = new RoutedUICommand();
CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
// ...
}
Da ich nun den gesamten Code zusammenhalten wollte, kann ich mit einem Nur-Code-Ansatz für Befehle die folgenden Methoden in die obige Klasse einfügen:
/// Closes the window provided as a parameter
public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e)
{
((Window)e.Parameter).Close();
}
/// Allows a Command to execute if the CommandParameter is not a null value
public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
e.Handled = true;
}
Die dortige zweite Methode kann sogar mit anderen Befehlen geteilt werden, ohne dass ich sie überall wiederholen muss.
Sobald Sie die Befehle auf diese Weise definiert haben, können Sie sie zu jedem Teil der Benutzeroberfläche hinzufügen.Im Folgenden füge ich nach dem Laden des Fensters Befehlsbindungen sowohl zum Fenster als auch zum MenuItem hinzu und füge dann mithilfe einer Schleife eine Eingabebindung zum Fenster hinzu, um dies für alle Befehlsbindungen zu tun.Der übergebene Parameter ist das Fenster selbst, sodass der obige Code weiß, welches Fenster er schließen soll.
public partial class SimpleWindow : Window
{
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// ...
this.CommandBindings.Add(
new CommandBinding(
CommandBank.CloseWindow,
CommandBank.CloseWindowExecute,
CommandBank.CanExecuteIfParameterIsNotNull));
foreach (CommandBinding binding in this.CommandBindings)
{
RoutedCommand command = (RoutedCommand)binding.Command;
if (command.InputGestures.Count > 0)
{
foreach (InputGesture gesture in command.InputGestures)
{
var iBind = new InputBinding(command, gesture);
iBind.CommandParameter = this;
this.InputBindings.Add(iBind);
}
}
}
// menuItemExit is defined in XAML
menuItemExit.Command = CommandBank.CloseWindow;
menuItemExit.CommandParameter = this;
// ...
}
// ....
}
Ich habe dann später auch Ereignishandler für die Ereignisse WindowClosing und WindowClosed. Ich empfehle Ihnen, die eigentliche Implementierung von Befehlen so klein und allgemein wie möglich zu gestalten.Da ich in diesem Fall nicht versucht habe, Code einzufügen, der versucht, das Schließen des Fensters zu stoppen, wenn nicht gespeicherte Daten vorhanden sind, habe ich diesen Code fest im WindowClosing-Ereignis belassen.
Lassen Sie mich wissen, wenn Sie weitere Fragen haben.:) :)
Andere Tipps
Ich habe letztes Jahr über eine Reihe von Ressourcen zu WPF-Befehlen zusammen mit einem Beispiel gebloggt unter http://blogs.vertigo.com/personal/alanl/Blog/archive/2007/05/31/commands-in-wpf.aspx
Hier einfügen:
Adam Nathans Beispielkapitel über wichtige neue Konzepte in WPF:Befehle
MSDN-Artikel:Das Befehlsmuster in WPF
Keyvan Nayyeri:So fügen Sie Befehle zur benutzerdefinierten WPF-Steuerung hinzu
Ian Griffiths:Avalon-Eingabe, Befehle und Handler
MSDN-Bibliothek:Beherrschender Überblick
MSDN-Bibliothek:CommandBinding-Klasse
MSDN-Bibliothek:Anleitungsthemen zu Eingaben und Befehlen
MSDN-Bibliothek:EditingCommands-Klasse
MSDN-Bibliothek:MediaCommands-Klasse
MSDN-Bibliothek:ApplicationCommands-Klasse
MSDN-Bibliothek:NavigationCommands-Klasse
MSDN-Bibliothek:ComponentCommands-Klasse
Außerdem ist in den WPF SDK-Beispielen ein schönes Beispiel für die RichTextBox-Bearbeitung vergraben, das ich erweitert habe.Du findest es hier: RichTextEditor.zip
In der Septemberausgabe 2008 des MSDN-Magazins hat Brian Noyes einen hervorragenden Artikel über RoutedCommand/RoutedEvents!!!
Hier ist der Link:http://msdn.microsoft.com/en-us/magazine/cc785480.aspx
Das Besondere an XAML ist, dass es für „einfache“ Programme in Ordnung ist, aber leider nicht gut funktioniert, wenn Sie Dinge wie Freigabefunktionen ausführen möchten.Angenommen, Sie haben mehrere Klassen und Benutzeroberflächen, die alle Befehle hatten, die nie deaktiviert wurden, dann müssten Sie für jedes Fenster oder UserControl eine „CanAlwaysExecute“-Methode schreiben!Das ist einfach nicht sehr TROCKEN.
Nachdem ich mehrere Blogs gelesen und verschiedene Dinge ausprobiert habe, habe ich mich entschieden, XAML ausschließlich auf Aussehen, Stile, Animationen und Trigger zu konzentrieren.Die gesamte Verknüpfung von Event-Handlern und Befehlen erfolgt jetzt im Code-Behind.:) :)
Ein weiteres Problem ist übrigens die Eingabebindung. Damit sie abgefangen wird, muss der Fokus auf dem Objekt liegen, das die Eingabebindungen enthält.Um beispielsweise eine Verknüpfung zu haben, die Sie jederzeit verwenden können (z. B. F1 zum Öffnen der Hilfe), muss diese Eingabebindung für das Window-Objekt festgelegt werden, da dieses immer den Fokus hat, wenn Ihre App aktiv ist.Die Verwendung der Code-Methode sollte dies einfacher machen, selbst wenn Sie mit der Verwendung von UserControls beginnen, die möglicherweise Eingabebindungen zu ihrem übergeordneten Fenster hinzufügen möchten.