Sdílet prostřednictvím


Přehled příkazů

Příkazování je vstupní mechanismus ve Windows Presentation Foundation (WPF), který poskytuje zpracování vstupu na sémantické úrovni než vstup zařízení. Příklady příkazů jsou operace Kopírovat, Vyjmout a Vložit nalezené v mnoha aplikacích.

Tento přehled definuje, které příkazy jsou ve WPF, které třídy jsou součástí příkazového modelu a jak používat a vytvářet příkazy v aplikacích.

Toto téma obsahuje následující části:

Co jsou příkazy

Příkazy mají několik účelů. Prvním účelem je oddělit sémantiku a objekt, který vyvolá příkaz z logiky, která příkaz spustí. To umožňuje, aby více a různorodých zdrojů vyvolalo stejnou logiku příkazu a umožnilo přizpůsobení logiky příkazů pro různé cíle. Například operace úprav kopírovat, vyjmout a vložit, které jsou nalezeny v mnoha aplikacích, lze vyvolat pomocí různých uživatelských akcí, pokud jsou implementovány pomocí příkazů. Aplikace může uživateli umožnit vyjmout vybrané objekty nebo text buď kliknutím na tlačítko, výběrem položky v nabídce nebo pomocí kombinace kláves, například CTRL+X. Pomocí příkazů můžete svázat každý typ akce uživatele se stejnou logikou.

Dalším účelem příkazů je indikovat, jestli je akce k dispozici. Pokud chcete pokračovat v příkladu vyjmutí objektu nebo textu, má akce smysl pouze v případě, že je vybráno něco. Pokud se uživatel pokusí vyjmout objekt nebo text bez výběru, nic se nestane. Pokud to chcete uživateli označit, mnoho aplikací zakáže tlačítka a položky nabídky, aby uživatel věděl, jestli je možné provést akci. Příkaz může indikovat, zda je akce možná implementací CanExecute metody. Tlačítko se může přihlásit k odběru CanExecuteChanged události a být zakázáno, pokud CanExecute se vrátí false nebo je povoleno, pokud CanExecute se vrátí true.

Sémantika příkazu může být konzistentní napříč aplikacemi a třídami, ale logika akce je specifická pro konkrétní objekt, na který se pracuje. Kombinace kláves CTRL+X vyvolá příkaz Vyjmoutve třídách textu, třídách obrázků a webových prohlížečích, ale skutečná logika pro provedení operace Vyjmutí je definována aplikací, která provede vyjmutí. A RoutedCommand umožňuje klientům implementovat logiku. Textový objekt může vybraný text vyjmout do schránky, zatímco objekt obrázku může vybraný obrázek vyjmout. Když aplikace zpracovává Executed událost, má přístup k cíli příkazu a může provést odpovídající akci v závislosti na typu cíle.

Příklad jednoduchého příkazu ve WPF

Nejjednodušší způsob, jak použít příkaz ve WPF, je použít předdefinovaný RoutedCommand z jedné z tříd knihovny příkazů, použít ovládací prvek, který má nativní podporu pro zpracování příkazu, a použít ovládací prvek, který má nativní podporu pro vyvolání příkazu. Příkaz Paste je jedním z předdefinovaných příkazů ve ApplicationCommands třídě. Ovládací TextBox prvek má integrovanou logiku Paste pro zpracování příkazu. MenuItem Třída má nativní podporu pro vyvolání příkazů.

Následující příklad ukazuje, jak nastavit tak MenuItem , aby po kliknutí Paste vyvolá příkaz na , TextBoxza předpokladu, že TextBox má fokus klávesnice.

<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

Čtyři hlavní koncepty v commandingu WPF

Směrovaný model příkazů ve WPF je možné rozdělit do čtyř hlavních konceptů: příkaz, zdroj příkazů, cíl příkazu a vazba příkazu:

  • Příkaz je akce, která se má provést.

  • Zdroj příkazu je objekt, který příkaz vyvolá.

  • Cílem příkazu je objekt, na který se příkaz spouští.

  • Vazba příkazu je objekt, který mapuje logiku příkazu na příkaz.

V předchozím příkladu Paste je příkaz příkazem, MenuItem jedná se o zdroj příkazů, TextBox cíl příkazu a vazbu příkazů poskytuje TextBox ovládací prvek. Stojí za zmínku, že není vždy případ, že CommandBinding je dodán ovládacím prvku, který je cílovou třídou příkazu. Vývojář aplikace musí vytvořit poměrně často CommandBinding , nebo CommandBinding může být připojen k nadřazenému objektu cíle příkazu.

Příkazy

Příkazy ve WPF jsou vytvořeny implementací ICommand rozhraní. ICommand zveřejňuje dvě metody, Executea CanExecutea , a událost, CanExecuteChanged. Execute provede akce přidružené k příkazu. CanExecute určuje, zda se příkaz může spustit v aktuálním cíli příkazu. CanExecuteChanged je vyvolána, pokud správce příkazů, který centralizuje příkazové operace, zjistí změnu ve zdroji příkazů, která může zneplatnit příkaz, který byl vyvolán, ale dosud nebyl proveden vazbou příkazu. Implementace WPF ICommand je RoutedCommand třída a je cílem tohoto přehledu.

Hlavními zdroji vstupu ve WPF jsou myš, klávesnice, rukopis a směrované příkazy. Čím více vstupů orientovaných na zařízení, používá RoutedEvent objekty na stránce aplikace, že došlo ke vstupní události. A RoutedCommand se nijak neliší. A ExecuteCanExecute metody RoutedCommand neobsahují logiku aplikace pro příkaz, ale spíše vyvolávají směrované události, které tunelují a bublinou přes strom elementu, dokud nenarazí na objekt s objektem CommandBinding. Obsahuje CommandBinding obslužné rutiny pro tyto události a jedná se o obslužné rutiny, které provádějí příkaz. Další informace o směrování událostí ve WPF naleznete v tématu Přehled směrovaných událostí.

Metoda Execute na objektu RoutedCommand vyvolá PreviewExecutedExecuted události v cíli příkazu. Metoda CanExecute u objektu RoutedCommandCanExecute vyvolá události PreviewCanExecute v cíli příkazu. Tyto události tunelují a bublinují stromem prvků, dokud nenarazí na objekt, který má CommandBinding pro daný příkaz.

WPF poskytuje sadu běžných směrovaných příkazů rozložených do několika tříd: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommandsa EditingCommands. Tyto třídy se skládají pouze z RoutedCommand objektů, a ne z logiky implementace příkazu. Logika implementace je zodpovědností objektu, na kterém se příkaz spouští.

Zdroje příkazů

Zdroj příkazu je objekt, který příkaz vyvolá. Příklady zdrojů příkazů jsou MenuItem, Buttona KeyGesture.

Zdroje příkazů ve WPF obecně implementují ICommandSource rozhraní.

ICommandSource zveřejňuje tři vlastnosti: Command, CommandTargeta CommandParameter:

Třídy WPF, které implementují ICommandSource jsou ButtonBase, MenuItem, Hyperlinka InputBinding. ButtonBase, MenuItema Hyperlink vyvolá příkaz po kliknutí a InputBinding vyvolá příkaz, když se InputGesture k němu přidružuje.

Následující příklad ukazuje, jak použít MenuItem jako ContextMenu zdroj příkazů pro Properties příkaz.

<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

Zdroj příkazů obvykle naslouchá CanExecuteChanged události. Tato událost informuje zdroj příkazů, že se mohla změnit schopnost příkazu spustit v aktuálním cíli příkazu. Zdroj příkazu může pomocí metody dotazovat aktuální stav objektu RoutedCommandCanExecute . Zdroj příkazu se pak může zakázat, pokud příkaz nejde spustit. Příkladem je MenuItem samotný šedivý, když příkaz nemůže provést.

Jako InputGesture zdroj příkazů lze použít příkaz. Dva typy vstupních gest v WPF jsou a KeyGestureMouseGesture. Můžete si představit klávesovou zkratku KeyGesture , například CTRL+C. A KeyGesture se skládá ze Key sady ModifierKeys. A MouseGesture se skládá z MouseAction a volitelné sady .ModifierKeys

Aby InputGesture objekt fungoval jako zdroj příkazů, musí být přidružený k příkazu. Existuje několik způsobů, jak toho dosáhnout. Jedním ze způsobů je použít .InputBinding

Následující příklad ukazuje, jak vytvořit KeyBinding mezi a KeyGesture a 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)

Dalším způsobem, jak přidružit k InputGesture objektu, RoutedCommand je přidat do InputGesture objektu InputGestureCollectionRoutedCommand.

Následující příklad ukazuje, jak přidat KeyGesture do InputGestureCollection souboru 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

A CommandBinding přidruží příkaz k obslužným rutinám událostí, které tento příkaz implementují.

Třída CommandBinding obsahuje Command vlastnost, a PreviewExecuted, Executed, PreviewCanExecute, a CanExecute události.

Command je příkaz, ke CommandBinding kterému je přidružen. Obslužné rutiny událostí připojené k událostem PreviewExecuted a Executed události implementují logiku příkazu. Obslužné rutiny událostí připojené k událostem PreviewCanExecute a CanExecute určují, jestli se příkaz může spustit v aktuálním cíli příkazu.

Následující příklad ukazuje, jak vytvořit CommandBinding v kořenovém adresáři Window aplikace. Přidruží CommandBindingOpen příkaz a ExecutedCanExecute obslužné rutiny.

<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)

Dále se ExecutedRoutedEventHandler vytvoří a vytvoří CanExecuteRoutedEventHandler se. Otevře ExecutedRoutedEventHandler se MessageBox řetězec s informací, že byl příkaz proveden. CanExecute Nastaví CanExecuteRoutedEventHandler vlastnost na 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

A CommandBinding je připojen k určitému objektu, jako je kořen Window aplikace nebo ovládací prvek. Objekt, který CommandBinding je připojen k definování rozsahu vazby. Událost může například CommandBinding dosáhnout Executed připojeného k nadřazenému objektu cíle příkazu, ale CommandBinding nelze dosáhnout připojení k potomku cíle příkazu. To je přímý důsledek způsobu, jakým tunely RoutedEvent a bubliny z objektu, který vyvolá událost.

V některých situacích CommandBinding je připojen k samotnému cíli příkazu, například s TextBox třídou a příkazy Cut, Copya Paste příkazy. Poměrně často je však vhodnější připojit CommandBinding k nadřazeného objektu příkazového cíle, jako je hlavní Window objekt nebo objekt aplikace, zejména v případě, že stejný CommandBinding lze použít pro více cílů příkazů. Jedná se o rozhodnutí o návrhu, která byste měli zvážit při vytváření infrastruktury příkazů.

Cíl příkazu

Cíl příkazu je prvek, na kterém se příkaz spustí. Pokud jde o cíl RoutedCommandpříkazu, je prvek, na kterém se směruje Executed a CanExecute začíná. Jak jsme uvedli dříve, ve WPF CommandTarget vlastnost ICommandSource je použitelná pouze v případě, že je RoutedCommand.ICommand CommandTarget Pokud je nastavený na objektu ICommandSource a odpovídající příkaz není , RoutedCommandcíl příkazu se ignoruje.

Zdroj příkazů může explicitně nastavit cíl příkazu. Pokud cíl příkazu není definovaný, použije se jako cíl příkazu prvek s fokusem klávesnice. Jednou z výhod použití elementu s fokusem klávesnice jako cíl příkazu je, že vývojář aplikace může použít stejný zdroj příkazů k vyvolání příkazu na více cílech, aniž by musel sledovat cíl příkazu. Pokud například MenuItem vyvolá příkaz Vložit v aplikaci, která má TextBox ovládací prvek a PasswordBox ovládací prvek, může být cílem buď PasswordBoxTextBox nebo v závislosti na tom, který ovládací prvek má fokus klávesnice.

Následující příklad ukazuje, jak explicitně nastavit cíl příkazu v kódu a kód za.

<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

Správce příkazů

Slouží CommandManager k řadě funkcí souvisejících s příkazy. Poskytuje sadu statických metod pro přidávání a odebírání PreviewExecuted, Executed, PreviewCanExecutea CanExecute obslužné rutiny událostí do a z konkrétního prvku. Poskytuje prostředky pro registraci CommandBinding a InputBinding objekty do konkrétní třídy. Poskytuje CommandManager také prostředky, které prostřednictvím RequerySuggested události upozorňují příkaz, když by měla CanExecuteChanged vyvolat událost.

Metoda InvalidateRequerySuggested vynutí CommandManager vyvolání RequerySuggested události. To je užitečné pro podmínky, které by měly zakázat nebo povolit příkaz, ale nejsou to podmínky, o kterých CommandManager si je vědom.

Knihovna příkazů

WPF poskytuje sadu předdefinovaných příkazů. Knihovna příkazů se skládá z následujících tříd: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommandsa ComponentCommands. Tyto třídy poskytují příkazy, jako Cutjsou , BrowseBack a BrowseForward, Play, Stopa Pause.

Mnoho z těchto příkazů obsahuje sadu výchozích vstupních vazeb. Pokud například určíte, že aplikace zpracovává příkaz pro kopírování, automaticky získáte vazbu klávesnice CTRL+C. Získáte také vazby pro jiná vstupní zařízení, jako jsou gesta pera tabletu a informace o řeči.

Když odkazujete na příkazy v různých knihovnách příkazů pomocí XAML, můžete obvykle vynechat název třídy knihovny, která zveřejňuje statickou vlastnost příkazu. Obecně platí, že názvy příkazů jsou jednoznačné jako řetězce a vlastnící typy existují, aby poskytovaly logické seskupení příkazů, ale nejsou nezbytné pro nejednoznačnost. Můžete například zadat Command="Cut" místo toho, aby bylo více sloves Command="ApplicationCommands.Cut". Jedná se o mechanismus pohodlí, který je integrovaný v procesoru WPF XAML pro příkazy (přesněji řečeno, jedná se o chování převaděče ICommandtypů , které WPF XAML procesor odkazuje při načítání).

Vytváření vlastních příkazů

Pokud příkazy v třídách knihovny příkazů nevyhovují vašim potřebám, můžete vytvořit vlastní příkazy. Vlastní příkaz můžete vytvořit dvěma způsoby. První je začít od základů a implementovat ICommand rozhraní. Druhým způsobem a častějším přístupem je vytvořit nebo RoutedCommand vytvořit RoutedUICommand.

Příklad vytvoření vlastního RoutedCommandobjektu najdete v tématu Vytvoření vlastní ukázky RoutedCommand.

Viz také