Cenni preliminari sull'esecuzione di comandi
Aggiornamento: novembre 2007
L'esecuzione di comandi è un meccanismo di input di Windows Presentation Foundation (WPF) che fornisce la gestione di input a un livello semantico maggiore rispetto all'input del dispositivo. Le operazioni Copia, Taglia e Incolla presenti in molte applicazioni sono esempi di comandi.
In questi cenni preliminari vengono definiti i comandi presenti in WPF, le classi che fanno parte del modello di esecuzione di comandi e la modalità di utilizzo e di creazione di comandi all'interno delle applicazioni.
Nel presente argomento sono contenute le seguenti sezioni.
- Definizione dei comandi
- Esempio di comando semplice in WPF
- Quattro concetti principali relativi all'esecuzione di comandi in WPF
- Libreria dei comandi
- Creazione di comandi personalizzati
- Argomenti correlati
Definizione dei comandi
Il sistema di esecuzione di comandi di WPF si basa sugli oggetti RoutedCommand e RoutedEvent. Un comando non deve essere necessariamente RoutedCommand ed è sufficiente che implementi l'oggetto ICommand, che sarà illustrato in seguito; tuttavia la maggior parte di questi cenni preliminari è incentrata sul modello RoutedCommand.
La differenza tra i comandi e un semplice gestore eventi associato a un pulsante o a un timer consiste nel fatto che i comandi separano la semantica e la creazione di un'azione dalla relativa logica. In questo modo, più codici sorgente diversi possono richiamare la stessa logica di comando che pertanto può essere personalizzata per obiettivi differenti.
Le operazioni di modifica Copia, Taglia e Incolla presenti in molte applicazioni sono esempi di comandi. La semantica del comando è coerente tra le applicazioni e le classi, tuttavia la logica dell'azione è specifica dell'oggetto particolare su cui si agisce. La combinazione di tasti CTRL+X richiama il comando Taglia nelle classi di testo, nelle classi di immagine e nei browser Web, tuttavia la logica effettiva per l'esecuzione dell'operazione Taglia viene definita dall'oggetto o dall'applicazione su cui si sta eseguendo l'operazione di taglio e non nel codice sorgente che ha richiamato il comando. Un oggetto testo consente di tagliare il testo selezionato negli appunti, mentre un oggetto immagine permette di tagliare l'immagine selezionata, tuttavia la stessa origine comando, un pulsante KeyGesture o ToolBar consente di richiamare il comando in entrambe le classi.
Esempio di comando semplice in WPF
Il modo più semplice per utilizzare un comando in WPF consiste nell'utilizzo di un oggetto RoutedCommand predefinito di una delle classi della libreria dei comandi; nell'utilizzare un controllo che dispone del supporto nativo per gestire il comando; nell'utilizzare un controllo che dispone del supporto nativo per richiamare un comando. Il comando Paste è uno dei comandi predefiniti della classe ApplicationCommands. Il controllo TextBox dispone di una logica incorporata per la gestione del comando Paste. La classe MenuItem dispone del supporto nativo per richiamare i comandi.
Nell'esempio seguente viene mostrato come configurare un oggetto MenuItem in modo che, una volta selezionato, richiami il comando Paste su un oggetto TextBox, presupponendo che l'oggetto TextBox disponga dello stato attivo.
<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;
Quattro concetti principali relativi all'esecuzione di comandi in WPF
Il modello di comando indirizzato di WPF può essere suddiviso in quattro concetti principali: il comando, l'origine comando, la destinazione comando e l'associazione comando:
Il comando è l'azione da eseguire.
L'origine comando è l'oggetto che richiama il comando.
La destinazione comando è l'oggetto sul quale il comando viene eseguito.
L'associazione comando è l'oggetto che esegue il mapping della logica di comando al comando.
Nell'esempio precedente, il comando Paste rappresenta il comando, l'oggetto MenuItem rappresenta l'origine comando, l'oggetto TextBox rappresenta la destinazione comando e l'associazione comando viene fornita dal controllo TextBox. È importante notare che non sempre l'oggetto CommandBinding viene fornito dal controllo che rappresenta la classe di destinazione comando. Spesso, l'oggetto CommandBinding deve essere creato dallo sviluppatore di applicazioni oppure potrebbe essere associato a un predecessore della destinazione comando.
Comandi
Vengono creati comandi in WPF implementando l'interfaccia ICommand. ICommand espone due metodi, Executee CanExecutee un evento, CanExecuteChanged. Execute esegue le azioni associate al comando. CanExecute determina se sia possibile eseguirlo sulla destinazione corrente. Viene generato CanExecuteChangedse il gestore che centralizza le operazioni di comando rileva una modifica nell'origine del comando che potrebbe invalidare un comando generato ma non ancora eseguito dall'associazione del comando. L'implementazione WPF dell'oggetto ICommand è la classe RoutedCommand e rappresenta l'oggetto di discussione principale di questi cenni preliminari.
Le origini di input principali di WPF sono il mouse, la tastiera, l'input penna e i comandi indirizzati. La maggior parte degli input orientati al dispositivo utilizzano un oggetto RoutedEvent per notificare agli oggetti di una pagina dell'applicazione che si è verificato un evento di input. Un oggetto RoutedCommand non è diverso. I metodi Execute e CanExecute di un oggetto RoutedCommand non contengono la logica dell'applicazioni per il comando, piuttosto generano eventi indirizzati che effettuano il tunneling e il bubbling della struttura ad albero dell'elemento, finché non incontrano un oggetto con CommandBinding. Nell'oggetto CommandBinding sono contenuti i gestori di questi eventi, i quali eseguono il comando. Per ulteriori informazioni sul routing degli eventi in WPF, vedere Cenni preliminari sugli eventi indirizzati.
Il metodo Execute di un oggetto RoutedCommand genera gli eventi PreviewExecuted e Executed sulla destinazione comando. Il metodo CanExecute di un oggetto RoutedCommand genera gli eventi CanExecute e PreviewCanExecute sulla destinazione comando. Tali eventi eseguono il tunneling e il bubbling nella struttura ad albero dell'elemento finché non incontrano un oggetto che dispone di un oggetto CommandBinding per quel particolare comando.
In WPF viene fornito un set di comandi indirizzati comuni contenuti in più classi: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands e EditingCommands. Queste classi sono costituite solo da oggetti RoutedCommand e non dalla logica di implementazione del comando. La logica di implementazione è responsabilità dell'oggetto sul quale il comando viene eseguito.
Origini comando
Un origine comando è l'oggetto che richiama il comando. MenuItem, Button e KeyGesture sono esempi di origini comando.
In genere, le origini comando di WPF implementano l'interfaccia ICommandSource.
L'oggetto ICommandSource espone tre proprietà: Command, CommandTarget e CommandParameter:
La proprietà Command è il comando da eseguire quando viene richiamata l'origine comando.
La proprietà CommandTarget è l'oggetto su cui eseguire il comando. È importante notare che in WPF la proprietà CommandTarget di ICommandSource può essere applicata solo quando l'oggetto ICommand è un oggetto RoutedCommand. Se la proprietà CommandTarget viene impostata sull'oggetto ICommandSource e il comando corrispondente non è un oggetto RoutedCommand, la destinazione comando viene ignorata. Se la proprietà CommandTarget non viene impostata, l'elemento con lo stato attivo sarà la destinazione comando.
L'oggetto CommandParameter è un tipo di dati definito dall'utente utilizzato per passare informazioni ai gestori che implementano il comando.
Le classi WPF che implementano l'oggetto ICommandSource sono: ButtonBase, MenuItem, Hyperlink e InputBinding. Gli oggetti ButtonBase, MenuItem e Hyperlink richiamano un comando quando vengono selezionati, mentre l'oggetto InputBinding richiama un comando quando viene eseguito l'oggetto InputGesture associato.
Nell'esempio seguente viene illustrato come utilizzare MenuItem in ContextMenu come un'origine comando per il comando 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;
In genere, un'origine comando resterà in ascolto dell'evento CanExecuteChanged. Tale evento informa l'origine comando relativamente alla probabile modifica della capacità del comando di essere eseguito sulla destinazione comando corrente. L'origine comando può eseguire una query sullo stato corrente dell'oggetto RoutedCommand utilizzando il metodo CanExecute. L'origine comando può quindi disattivarsi, se l'esecuzione del comando non riesce. Un esempio viene fornito dal fatto che l'oggetto MenuItem diventa di colore grigio quando non è possibile eseguire un comando.
Un oggetto InputGesture può essere utilizzato come origine comando. Gli oggetti KeyGesture e MouseGesture sono due tipi di movimento di input di WPF. È possibile considerare un oggetto KeyGesture come un tasto di scelta rapida, ad esempio CTRL+C. Un oggetto KeyGesture è costituito da un oggetto Key e da un insieme di oggetti ModifierKeys. Un oggetto MouseGesture è costituito da un oggetto MouseAction e da un insieme facoltativo di oggetti ModifierKeys.
Affinché un oggetto InputGesture funzioni come origine comando, deve essere associato a un comando. Questa operazione può essere eseguita in diversi modi. Uno di questi consiste nell'utilizzare un oggetto InputBinding.
Nell'esempio seguente viene illustrato come creare un oggetto KeyBinding tra un oggetto KeyGesture e un oggetto 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);
Un altro modo per associare un oggetto InputGesture a un oggetto RoutedCommand consiste nell'aggiungere InputGesture all'oggetto InputGestureCollection nell'oggetto RoutedCommand.
Nell'esempio seguente viene illustrato come aggiungere un oggetto KeyGesture all'oggetto InputGestureCollection di un oggetto RoutedCommand.
KeyGesture OpenCmdKeyGesture = new KeyGesture(
Key.B,
ModifierKeys.Control);
ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);
CommandBinding
Un oggetto CommandBinding associa un comando ai gestori eventi che implementano il comando.
La classe CommandBinding contiene una proprietà Command e gli eventi PreviewExecuted, Executed, PreviewCanExecute e CanExecute.
L'oggetto Command è il comando a cui è associato l'oggetto CommandBinding. I gestori eventi associati agli eventi PreviewExecuted e Executed implementano la logica di comando. I gestori eventi associati agli eventi PreviewCanExecute e CanExecute determinano se il comando può essere eseguito nella destinazione comando corrente.
Nell'esempio seguente viene mostrato come creare un oggetto CommandBinding nella radice Window di un'applicazione. L'oggetto CommandBinding associa il comando Open ai gestori Executed e CanExecute.
<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);
Successivamente, vengono creati gli oggetti ExecutedRoutedEventHandler e CanExecuteRoutedEventHandler. ExecutedRoutedEventHandler consente di aprire un oggetto MessageBox nel quale viene visualizzata una stringa che conferma l'esecuzione del comando. L'oggetto CanExecuteRoutedEventHandler imposta la proprietà CanExecute su true.
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 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 OpenCmdCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
Un oggetto CommandBinding viene associato a un oggetto specifico, ad esempio la radice Window dell'applicazione o di un controllo. L'oggetto a cui è associato l'oggetto CommandBinding definisce l'ambito dell'associazione. Ad esempio, un oggetto CommandBinding associato a un predecessore della destinazione comando può essere raggiunto dall'evento Executed, mentre un oggetto CommandBinding associato a un discendente della destinazione comando non può essere raggiunto. Si tratta di una conseguenza diretta del modo in cui un oggetto RoutedEvent effettua il tunneling e il bubbling dall'oggetto che genera l'evento.
In alcune situazioni, l'oggetto CommandBinding viene associato alla destinazione comando stessa, ad esempio con la classe TextBox e i comandi Cut, Copye Paste. Tuttavia, spesso è consigliabile associare l'oggetto CommandBinding a un predecessore della destinazione comando, ad esempio l'oggetto Window principale o l'oggetto Application, specialmente se lo stesso oggetto CommandBinding può essere utilizzato per più destinazioni comando. Si tratta di decisioni di progettazione da considerare quando si crea l'infrastruttura di esecuzione di comandi.
Destinazione comando
La destinazione comando è l'elemento sul quale viene eseguito il comando. Per quanto riguarda un oggetto RoutedCommand, la destinazione comando è l'elemento a partire dal quale viene avviato il routing degli eventi Executed e CanExecute. Come indicato in precedenza, in WPF la proprietà CommandTarget dell'oggetto ICommandSource può essere applicata solo se l'oggetto ICommand è un oggetto RoutedCommand. Se l'oggetto CommandTarget viene impostato su ICommandSource e il comando corrispondente non è un oggetto RoutedCommand, la destinazione comando viene ignorata.
L'origine comando può impostare in modo esplicito la destinazione comando. Se quest'ultima non viene definita, l'elemento con lo stato attivo sarà utilizzato come destinazione comando. Uno dei vantaggi dell'utilizzo dell'elemento con lo stato attivo come destinazione comando consiste nel fatto che consente allo sviluppatore di applicazioni di utilizzare la stessa origine comando per richiamare un comando su più destinazioni senza tenere traccia della destinazione comando. Se, ad esempio, l'oggetto MenuItem richiama il comando Incolla in un'applicazione che dispone di un controllo TextBox e di un controllo PasswordBox, la destinazione può essere l'oggetto TextBox oppure l'oggetto PasswordBox, in base al controllo che dispone dello stato attivo.
Nell'esempio seguente viene mostrato come impostare in modo esplicito la destinazione comando nel markup e nel code behind.
<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;
CommandManager
L'oggetto CommandManager è utile per molte funzioni relative ai comandi. Rende disponibile un insieme di metodi statici per aggiungere e rimuovere i gestori eventi PreviewExecuted, Executed, PreviewCanExecute e CanExecute da un elemento specifico nonché un modo per registrare gli oggetti CommandBinding e InputBinding in una classe specifica. L'oggetto CommandManager fornisce inoltre un modo, tramite l'evento RequerySuggested, per notificare a un comando il momento in cui deve generare l'evento CanExecuteChanged.
Il metodo InvalidateRequerySuggested forza l'oggetto CommandManager di generare l'evento RequerySuggested. Ciò è utile per le condizioni che richiedono l'attivazione o la disattivazione di un comando ma che l'oggetto CommandManager non è in grado di rilevare. Per un esempio di chiamata al metodo InvalidateRequerySuggested per imporre a un oggetto CommandManager di generare l'evento RequerySuggested, vedere l'esempio Esempio Disable Command Source via Dispatcher Timer.
Libreria dei comandi
In WPF viene fornito un insieme di comandi predefiniti. La libreria dei comandi include le classi seguenti: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommands e ComponentCommands. Tali classi forniscono comandi, quali Cut, BrowseBack e BrowseForward, Play, Stop e Pause.
Molti di questi comandi includono un insieme di associazioni di input predefinite. Se, ad esempio, si specifica che l'applicazione gestisce il comando di copia, si ottiene automaticamente l'associazione di tastiera "CTRL + C". Si ottengono inoltre associazioni per altri dispositivi di input, quali i movimenti della penna Tablet PC e informazioni sulle funzioni vocali.
Quando si fa riferimento ai comandi delle diverse librerie dei comandi utilizzando XAML, in genere è possibile omettere il nome classe della classe di libreria che espone la proprietà del comando statico. Di solito i nomi dei comandi sono stringhe non ambigue ed esistono tipi proprietari che forniscono un raggruppamento logico di comandi, ma che non sono necessari per la risoluzione dell'ambiguità. È possibile, ad esempio, specificare Command="Cut" anziché l'oggetto Command="ApplicationCommands.Cut" più dettagliato. Si tratta di un meccanismo utile incorporato nel processore XAML WPF per i comandi (più precisamente, si tratta di un comportamento del convertitore dei tipi di ICommand al quale il processore XAML WPF fa riferimento in fase di caricamento).
Creazione di comandi personalizzati
Se i comandi delle classi della libreria dei comandi non soddisfano le proprie esigenze, è possibile creare comandi personalizzati. Questa operazione può essere eseguita in due modi. Il primo prevede la progettazione da zero e l'implementazione dell'interfaccia ICommand. Il secondo, che costituisce l'approccio più comune, consiste nel creare un oggetto RoutedCommand o un oggetto RoutedUICommand.
Per un esempio relativo alla creazione di un oggetto RoutedCommand personalizzato, vedere Esempio di creazione di un RoutedCommand personalizzato.
Vedere anche
Attività
Esempio di creazione di un RoutedCommand personalizzato
Procedura: implementare ICommandSource
Procedura: aggiungere un comando a un oggetto MenuItem
Esempio Disable Command Source via Dispatcher Timer
Concetti
Cenni preliminari sugli eventi indirizzati