Delen via


Overzicht van opdrachten

Commanding is een invoermechanisme in Windows Presentation Foundation (WPF) dat invoerverwerking biedt op een meer semantisch niveau dan apparaatinvoer. Voorbeelden van opdrachten zijn de Copy, Cuten Paste-bewerkingen in veel toepassingen.

In dit overzicht wordt gedefinieerd welke opdrachten zich in WPF bevinden, welke klassen deel uitmaken van het opdrachtmodel en hoe u opdrachten in uw toepassingen kunt gebruiken en maken.

Dit onderwerp bevat de volgende secties:

Wat zijn opdrachten?

Opdrachten hebben verschillende doeleinden. Het eerste doel is het scheiden van de semantiek en het object dat een opdracht aanroept van de logica waarmee de opdracht wordt uitgevoerd. Hierdoor kunnen meerdere en verschillende bronnen dezelfde opdrachtlogica aanroepen en kan de opdrachtlogica worden aangepast voor verschillende doelen. De bewerkingen Kopiëren, Knippenen Plakken, die in veel toepassingen worden gevonden, kunnen bijvoorbeeld worden aangeroepen met behulp van verschillende gebruikersacties als ze worden geïmplementeerd met behulp van opdrachten. Een toepassing kan een gebruiker toestaan geselecteerde objecten of tekst te knippen door op een knop te klikken, een item in een menu te kiezen of een toetsencombinatie te gebruiken, zoals Ctrl+X. Met behulp van opdrachten kunt u elk type gebruikersactie binden aan dezelfde logica.

Een ander doel van opdrachten is om aan te geven of een actie beschikbaar is. Als u wilt doorgaan met het voorbeeld van het knippen van een object of tekst, is de actie alleen zinvol wanneer er iets wordt geselecteerd. Als een gebruiker probeert een object of tekst te knippen zonder iets te selecteren, gebeurt er niets. Om dit aan de gebruiker aan te geven, schakelen veel toepassingen knoppen en menu-items uit, zodat de gebruiker weet of het mogelijk is om een actie uit te voeren. Een opdracht kan aangeven of een actie mogelijk is door de CanExecute methode te implementeren. Een knop kan zich abonneren op de CanExecuteChanged gebeurtenis en worden uitgeschakeld als CanExecutefalse retourneert of wordt ingeschakeld als CanExecutetrueretourneert.

De semantiek van een opdracht kan consistent zijn in toepassingen en klassen, maar de logica van de actie is specifiek voor het specifieke object waarop is gereageerd. Met de toetsencombinatie Ctrl+X wordt de opdracht Knippen aangeroepen in tekstklassen, afbeeldingsklassen en webbrowsers, maar de werkelijke logica voor het uitvoeren van de bewerking Knippen wordt gedefinieerd door de toepassing waarmee de knip wordt uitgevoerd. Met een RoutedCommand kunnen clients de logica implementeren. Een tekstobject kan de geselecteerde tekst knippen in het klembord, terwijl een afbeeldingsobject de geselecteerde afbeelding kan knippen. Wanneer een toepassing de Executed gebeurtenis afhandelt, heeft deze toegang tot het doel van de opdracht en kan deze de juiste actie ondernemen, afhankelijk van het type doel.

Voorbeeld van eenvoudige opdracht in WPF

De eenvoudigste manier om een opdracht te gebruiken in WPF is het gebruik van een vooraf gedefinieerde RoutedCommand uit een van de opdrachtbibliotheekklassen; een besturingselement gebruiken met systeemeigen ondersteuning voor het verwerken van de opdracht; en gebruik een besturingselement met systeemeigen ondersteuning voor het aanroepen van een opdracht. De Paste opdracht is een van de vooraf gedefinieerde opdrachten in de klasse ApplicationCommands. Het besturingselement TextBox heeft ingebouwde logica voor het afhandelen van de opdracht Paste. En de MenuItem-klasse biedt systeemeigen ondersteuning voor het aanroepen van opdrachten.

In het volgende voorbeeld ziet u hoe u een MenuItem zo instelt dat wanneer erop wordt geklikt, de opdracht Paste op een TextBoxwordt aangeroepen, ervan uitgaande dat de TextBox de toetsenbordfocus heeft.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()

' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)

' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste

Vier hoofdconcepten in WPF-opdrachten

Het gerouteerde opdrachtmodel in WPF kan worden onderverdeeld in vier hoofdconcepten: de opdracht, de opdrachtbron, het opdrachtdoel en de opdrachtbinding:

  • De opdracht is de actie die moet worden uitgevoerd.

  • De opdrachtbron is het object dat de opdracht aanroept.

  • Het opdrachtdoel is het object waarop de opdracht wordt uitgevoerd.

  • De opdrachtbinding is het object waarmee de opdrachtlogica wordt toegewezen aan de opdracht.

In het vorige voorbeeld is de Paste opdracht de opdracht, de MenuItem de opdrachtbron, het TextBox het opdrachtdoel is en de opdrachtbinding wordt geleverd door het TextBox besturingselement. Het is de moeite waard om te vermelden dat het niet altijd het geval is dat de CommandBinding wordt geleverd door het besturingselement dat de opdrachtdoelklasse is. Vaak moet de CommandBinding door de toepassingsontwikkelaar worden aangemaakt, of de CommandBinding kan worden gekoppeld aan een voorouder van het opdrachtdoel.

Opdrachten

Opdrachten in WPF worden gemaakt door de ICommand-interface te implementeren. ICommand bevat twee methoden, Executeen CanExecute, en een gebeurtenis, CanExecuteChanged. Execute voert de acties uit die zijn gekoppeld aan de opdracht. CanExecute bepaalt of de opdracht kan worden uitgevoerd op het huidige opdrachtdoel. CanExecuteChanged wordt opgeworpen als de opdrachtbeheerder die de opdrachtbewerkingen centraliseert, een wijziging in de opdrachtbron detecteert die een opdracht, die reeds is opgeworpen maar nog niet is uitgevoerd door de opdrachtbinding, mogelijk ongeldig kan maken. De WPF-implementatie van ICommand is de RoutedCommand klasse en is de focus van dit overzicht.

De belangrijkste invoerbronnen in WPF zijn de muis, het toetsenbord, inkt en gerouteerde opdrachten. De meer apparaatgeoriënteerde invoeren een RoutedEvent om objecten op een toepassingspagina te informeren dat er een invoergebeurtenis heeft plaatsgevonden. Een RoutedCommand is niet anders. De methoden Execute en CanExecute van een RoutedCommand bevatten niet de logica van het commando, maar ze genereren gerouteerde gebeurtenissen die tunnelen en bubbelen door de elementstructuur totdat ze een object met een CommandBindingtegenkomen. De CommandBinding bevat de handlers voor deze gebeurtenissen en het zijn de handlers die de opdracht uitvoeren. Zie Overzicht van gerouteerde gebeurtenissenvoor meer informatie over gebeurtenisroutering in WPF.

Met de methode Execute op een RoutedCommand worden de PreviewExecuted en de Executed gebeurtenissen in het opdrachtdoel gegenereerd. Met de CanExecute-methode op een RoutedCommand worden de CanExecute- en PreviewCanExecute-evenementen geactiveerd op het opdrachtdoel. Deze gebeurtenissen tunnelen en bellen door de elementstructuur totdat ze een object tegenkomen met een CommandBinding voor die specifieke opdracht.

WPF levert een set algemene gerouteerde opdrachten verspreid over verschillende klassen: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommandsen EditingCommands. Deze klassen bestaan alleen uit de RoutedCommand objecten en niet uit de implementatielogica van de opdracht. De implementatielogica is de verantwoordelijkheid van het object waarop de opdracht wordt uitgevoerd.

Opdrachtbronnen

Een opdrachtbron is het object dat de opdracht aanroept. Voorbeelden van opdrachtbronnen zijn MenuItem, Buttonen KeyGesture.

Opdrachtbronnen in WPF implementeren over het algemeen de ICommandSource interface.

ICommandSource bevat drie eigenschappen: Command, CommandTargeten CommandParameter:

  • Command is de opdracht die moet worden uitgevoerd wanneer de opdrachtbron wordt aangeroepen.

  • CommandTarget is het object waarop de opdracht moet worden uitgevoerd. Het is de moeite waard om te vermelden dat in WPF de eigenschap CommandTarget op ICommandSource alleen van toepassing is wanneer de ICommand een RoutedCommandis. Als de CommandTarget is ingesteld op een ICommandSource en de bijbehorende opdracht geen RoutedCommandis, wordt het opdrachtdoel genegeerd. Als de CommandTarget niet is ingesteld, is het element met toetsenbordfocus het opdrachtdoel.

  • CommandParameter is een door de gebruiker gedefinieerd gegevenstype dat wordt gebruikt om informatie door te geven aan de handlers die de opdracht implementeren.

De WPF-klassen die ICommandSource implementeren, zijn ButtonBase, MenuItem, Hyperlinken InputBinding. ButtonBase, MenuItemen Hyperlink een opdracht aanroepen wanneer erop wordt geklikt en een InputBinding een opdracht aanroept wanneer de InputGesture eraan is gekoppeld.

In het volgende voorbeeld ziet u hoe u een MenuItem in een ContextMenu gebruikt als opdrachtbron voor de opdracht Properties.

<StackPanel>
  <StackPanel.ContextMenu>
    <ContextMenu>
      <MenuItem Command="ApplicationCommands.Properties" />
    </ContextMenu>
  </StackPanel.ContextMenu>
</StackPanel>
StackPanel cmdSourcePanel = new StackPanel();
ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem();

// Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem);

// Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties;
Dim cmdSourcePanel As New StackPanel()
Dim cmdSourceContextMenu As New ContextMenu()
Dim cmdSourceMenuItem As New MenuItem()

' Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem)

' Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties

Normaal gesproken luistert een opdrachtbron naar de gebeurtenis CanExecuteChanged. Met deze gebeurtenis wordt de opdrachtbron geïnformeerd dat de mogelijkheid van de opdracht om uit te voeren op het huidige opdrachtdoel kan zijn gewijzigd. De opdrachtbron kan een query uitvoeren op de huidige status van de RoutedCommand met behulp van de methode CanExecute. De opdrachtbron kan zichzelf vervolgens uitschakelen als de opdracht niet kan worden uitgevoerd. Een voorbeeld hiervan is dat een MenuItem zichzelf grijs maakt wanneer een opdracht niet kan worden uitgevoerd.

Een InputGesture kan worden gebruikt als opdrachtbron. Twee typen invoerbewegingen in WPF zijn de KeyGesture en MouseGesture. U kunt een KeyGesture beschouwen als een sneltoets, zoals Ctrl+C. Een KeyGesture bestaat uit een Key en een set ModifierKeys. Een MouseGesture bestaat uit een MouseAction en een optionele set ModifierKeys.

Als u een InputGesture wilt laten fungeren als een opdrachtbron, moet deze zijn gekoppeld aan een opdracht. Er zijn een aantal manieren om dit te bereiken. Een manier is om een InputBindingte gebruiken.

In het volgende voorbeeld ziet u hoe u een KeyBinding maakt tussen een KeyGesture en een RoutedCommand.

<Window.InputBindings>
  <KeyBinding Key="B"
              Modifiers="Control" 
              Command="ApplicationCommands.Open" />
</Window.InputBindings>
KeyGesture OpenKeyGesture = new KeyGesture(
    Key.B,
    ModifierKeys.Control);

KeyBinding OpenCmdKeybinding = new KeyBinding(
    ApplicationCommands.Open,
    OpenKeyGesture);

this.InputBindings.Add(OpenCmdKeybinding);
Dim OpenKeyGesture As New KeyGesture(Key.B, ModifierKeys.Control)

Dim OpenCmdKeybinding As New KeyBinding(ApplicationCommands.Open, OpenKeyGesture)

Me.InputBindings.Add(OpenCmdKeybinding)

Een andere manier om een InputGesture aan een RoutedCommand te koppelen, is door de InputGesture toe te voegen aan de InputGestureCollection op de RoutedCommand.

In het volgende voorbeeld ziet u hoe u een KeyGesture toevoegt aan de InputGestureCollection van een RoutedCommand.

KeyGesture OpenCmdKeyGesture = new KeyGesture(
    Key.B,
    ModifierKeys.Control);

ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);
Dim OpenCmdKeyGesture As New KeyGesture(Key.B, ModifierKeys.Control)

ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture)

CommandBinding

Een CommandBinding koppelt een opdracht aan de gebeurtenis-handlers die de opdracht implementeren.

De klasse CommandBinding bevat een eigenschap Command en PreviewExecuted, Executed, PreviewCanExecuteen CanExecute gebeurtenissen.

Command is de opdracht waaraan de CommandBinding wordt gekoppeld. De gebeurtenis-handlers die zijn gekoppeld aan de PreviewExecuted en Executed gebeurtenissen implementeren de opdrachtlogica. De gebeurtenis-handlers die zijn gekoppeld aan de PreviewCanExecute en CanExecute gebeurtenissen bepalen of de opdracht kan worden uitgevoerd op het huidige opdrachtdoel.

In het volgende voorbeeld ziet u hoe u een CommandBinding maakt op de root Window van een toepassing. De CommandBinding koppelt de opdracht Open aan Executed en CanExecute handlers.

<Window.CommandBindings>
  <CommandBinding Command="ApplicationCommands.Open"
                  Executed="OpenCmdExecuted"
                  CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
    ApplicationCommands.Open,
    OpenCmdExecuted,
    OpenCmdCanExecute);

this.CommandBindings.Add(OpenCmdBinding);
' Creating CommandBinding and attaching an Executed and CanExecute handler
Dim OpenCmdBinding As New CommandBinding(ApplicationCommands.Open, AddressOf OpenCmdExecuted, AddressOf OpenCmdCanExecute)

Me.CommandBindings.Add(OpenCmdBinding)

Vervolgens worden de ExecutedRoutedEventHandler en de CanExecuteRoutedEventHandler gemaakt. De ExecutedRoutedEventHandler opent een MessageBox met een tekenreeks die aangeeft dat de opdracht is uitgevoerd. De CanExecuteRoutedEventHandler stelt de eigenschap CanExecute in op true.

void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)
{
    String command, targetobj;
    command = ((RoutedCommand)e.Command).Name;
    targetobj = ((FrameworkElement)target).Name;
    MessageBox.Show("The " + command +  " command has been invoked on target object " + targetobj);
}
Private Sub OpenCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
    Dim command, targetobj As String
    command = CType(e.Command, RoutedCommand).Name
    targetobj = CType(sender, FrameworkElement).Name
    MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj)
End Sub
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
}
Private Sub OpenCmdCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
    e.CanExecute = True
End Sub

Een CommandBinding is gekoppeld aan een specifiek object, zoals de hoofdmap Window van de toepassing of een besturingselement. Het object waaraan de CommandBinding is gekoppeld, definieert het bereik van de binding. Bijvoorbeeld, een CommandBinding die is gekoppeld aan een voorouder van het doeld, kan worden bereikt door de Executed gebeurtenis, maar een CommandBinding gekoppeld aan een afstammeling van het doeld kan niet worden bereikt. Dit is een direct gevolg van de manier waarop een RoutedEvent zich door en om het object dat het evenement oproept, voortbeweegt.

In sommige gevallen wordt de CommandBinding gekoppeld aan het opdrachtdoel zelf, zoals met de TextBox-klasse en de Cut, Copyen Paste opdrachten. Vaak is het echter handiger om de CommandBinding te koppelen aan een voorouder van het opdrachtdoel, zoals de hoofd-Window of het Toepassing-object, vooral als dezelfde CommandBinding kan worden gebruikt voor meerdere opdrachtdoelen. Dit zijn ontwerpbeslissingen die u moet overwegen wanneer u uw opdrachtinfrastructuur maakt.

Opdrachtdoel

Het opdrachtdoel is het element waarop de opdracht wordt uitgevoerd. Met betrekking tot een RoutedCommandis het opdrachtdoel het element waarop de routering van de Executed en CanExecute wordt gestart. Zoals eerder vermeld, is in WPF de eigenschap CommandTarget op ICommandSource alleen van toepassing wanneer de ICommand een RoutedCommandis. Als de CommandTarget is ingesteld op een ICommandSource en de bijbehorende opdracht geen RoutedCommandis, wordt het opdrachtdoel genegeerd.

De opdrachtbron kan het opdrachtdoel expliciet instellen. Als het opdrachtdoel niet is gedefinieerd, wordt het element met toetsenbordfocus gebruikt als het opdrachtdoel. Een van de voordelen van het gebruik van het element met toetsenbordfocus als het opdrachtdoel is dat de toepassingsontwikkelaar dezelfde opdrachtbron kan gebruiken om een opdracht op meerdere doelen aan te roepen zonder het opdrachtdoel bij te houden. Als een MenuItem bijvoorbeeld de opdracht Plakken aanroept in een toepassing met een TextBox en een PasswordBox besturingselement, kan het doel de TextBox of PasswordBox zijn, afhankelijk van welk besturingselement de toetsenbordfocus heeft.

In het volgende voorbeeld ziet u hoe u het opdrachtdoel expliciet instelt in markeringen en in code achter.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste"
              CommandTarget="{Binding ElementName=mainTextBox}" />
  </Menu>
  <TextBox Name="mainTextBox"/>
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()

' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)

' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste

De CommandManager

De CommandManager dient een aantal opdrachtgerelateerde functies. Het biedt een set statische methoden voor het toevoegen en verwijderen van PreviewExecuted, Executed, PreviewCanExecuteen CanExecute evenementhandlers naar en van een specifiek element. Het biedt een middel om CommandBinding en InputBinding objecten op een specifieke klasse te registreren. De CommandManager biedt ook een middel via de RequerySuggested gebeurtenis om een opdracht te melden wanneer deze de CanExecuteChanged gebeurtenis moet genereren.

De methode InvalidateRequerySuggested dwingt de CommandManager om de gebeurtenis RequerySuggested te veroorzaken. Dit is handig voor voorwaarden die een opdracht moeten uitschakelen/inschakelen, maar geen voorwaarden zijn waarvan de CommandManager op de hoogte is.

Opdrachtbibliotheek

WPF biedt een set vooraf gedefinieerde opdrachten. De opdrachtbibliotheek bestaat uit de volgende klassen: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommandsen de ComponentCommands. Deze klassen bieden opdrachten zoals Cut, BrowseBack en BrowseForward, Play, Stopen Pause.

Veel van deze opdrachten bevatten een set standaardinvoerbindingen. Als u bijvoorbeeld opgeeft dat uw toepassing de kopieeropdracht afhandelt, krijgt u automatisch de toetsenbordbinding Ctrl+C. U krijgt ook bindingen voor andere invoerapparaten, zoals penbewegingen voor tablet-pc's en spraakgegevens.

Wanneer u naar opdrachten in de verschillende opdrachtbibliotheken verwijst met behulp van XAML, kunt u meestal de klassenaam weglaten van de bibliotheekklasse waarmee de eigenschap statische opdracht wordt weergegeven. Over het algemeen zijn de opdrachtnamen eenduidig als tekenreeksen en bestaan de bijbehorende typen om een logische groepering van opdrachten te bieden, maar zijn niet nodig voor onderscheid. U kunt bijvoorbeeld Command="Cut" opgeven in plaats van de uitgebreidere Command="ApplicationCommands.Cut". Dit is een gemaksmechanisme dat is ingebouwd in de WPF XAML-processor voor opdrachten (meer precies, het is een typeconvertergedrag van ICommand, waarnaar de WPF XAML-processor verwijst bij het laden).

Aangepaste opdrachten maken

Als de opdrachten in de opdrachtbibliotheekklassen niet aan uw behoeften voldoen, kunt u uw eigen opdrachten maken. Er zijn twee manieren om een aangepaste opdracht te maken. De eerste is om van begin af aan te beginnen en de ICommand interface te implementeren. De andere manier, en de meer gebruikelijke benadering, is om een RoutedCommand of een RoutedUICommandte maken.

Zie voor een voorbeeld van het maken van een aangepaste RoutedCommand, de sectie 'Een voorbeeld van een aangepaste routeringsopdracht'.

Zie ook