Ricerca 
it-ITen-US
Register
Login
 
Author:  Patrizia Cosolo
Published:  2007/09/30

Panoramica del Sistema dei Comandi
Come iniziare a capire com'è fatto WPF (parte 5)

Questo articolo fa una breve panoramica del sistema dei Comandi di Windows Presentation Foundation (WPF), concetto completamente nuovo rispetto al modo in cui lavoriamo in Windows Forms, il Sistema dei Comandi e la Libreria dei comandi permettono di gestire ad esempio Copia, Incolla e altri comandi standard oppure di inventare dei comandi specifici per le nostre applicazioni.

Introduzione

Come i precedenti ed i successivi, questo articolo è una traduzione della serie dei Getting Started di Windows Presentation foundation che si trovano su MSDN. Indicherò i link agli articoli originali in inglese e i link correlati saranno tutti alla versione inglese, fatto salvo che, man mano che tradurrò gli articoli più interessanti aggancerò anche la versione in italiano. I link agli articoli saranno effettuati con i due segnalini standard:

  • Inglese che porterà alla versione originale inglese.
  • Italiano che porterà alla versione italiana quando questa sarà scritta.

 

Panoramica del Sistema dei Comandi

Il Sistema dei Comandi è un meccanismo di input di Windows Presentation Foundation (WPF) che offre un sistema per la gestione dell'input a livello di semantica piuttosto che di input del dispositivo. Esempi di comandi sono le operazioni di Copia(Copy), Taglia(Cut), e Incolla(Paste) che si trovano su numerose applicazioni.
Questa panoramica stabilisce quali comandi si trovano in WPF, quali sono le classi che fanno parte del modello del sistema dei comandi e come utilizzare e generare comandi nelle vostre applicazioni.
Il sistema dei comandi in WPF si basa sul RoutedCommand(Comando Pilotato) e sul RoutedEvent(Evento Pilotato). Gran parte di questa panoramica si concentrerà sul modello del RoutedCommand, anche se un comando non deve essere necessariamente un RoutedCommand ma semplicemente implementare l'interfaccia ICommand, della quale tratteremo in seguito.
Questo articolo contiene le seguenti sezioni:

Cosa sono i Comandi?

La differenza tra i comandi ed un semplice evento gestito, collegato ad un bottone o ad un timer, è che i comandi separano la semantica di un'azione dalla sua logica. Questo permette a molteplici ed eterogenee sorgenti di invocare la stessa logica di comando e concede a quest'ultima di essere personalizzata per destinatari diversi [targets n.d.t.].

Esempi di comandi sono le operazioni di modifica (editing) Copia, Taglia e Incolla, come abbiamo già ricordato. Le semantiche di un comando sono coerenti [consistent n.d.t.] attraverso [across n.d.t.] applicazioni e classi, ma la logica dell'azione è specifica per il particolare oggetto su cui ha effetto [acted upon:su cui agisce n.d.t.]. La combinazione di tasti Ctrl-C invoca il comando di Copia nelle classi di testo, nelle classi d'immagine e nei browsers del web, ma la reale logica d'esecuzione dell'operazione Copia è definita dall'oggetto o dall'applicazione sulla quale il taglio si sta verificando e non dalla sorgente che ha invocato il comando. Un oggetto di testo potrebbe copiare il testo selezionato all'interno della clipboard [gli appunti n.d.t.], mentre un oggetto d'immagine potrebbe copiare l'immagine selezionata, ma la stessa sorgente di comando, una KeyGesture [tasto funzione n.d.r.] o un Bottone di una ToolBar, può essere utilizzata per invocare il comando di entrambe le classi.

Esempio di Comando Semplice in WPF

Per utilizzare un comando in WPF ci sono tre possibilità molto semplici: ricorrere ad un RoutedCommand predefinito da una delle classi di libreria del comando; usare un controllo che possiede un supporto nativo per la gestione del comando; servirsi di un controllo che ha un supporto nativo per invocare un comando. Il comando Incolla è uno dei comandi predefiniti nella classe ApplicationCommands. Il controllo TextBox ha integrato [built in n.d.t.] la logica per la gestione del comando Incolla. La classe MenuItem possiede il supporto nativo per invocare comandi.
L'esempio seguente mostra come predisporre un MenuItem in modo che quando verrà cliccato invocherà il comando Incolla su una TestBox, supponendo che la Textbox  abbia il focus di tastiera [keyboard focus n.d.t.].

XAML

<StackPanel> 
   <Menu> 
      <MenuItem Command="ApplicationCommands.Paste" /> 
   Menu> 
   <TextBox /> 
StackPanel>

C#

// creazione oggetti UI
StackPanel mainStackPanel = new StackPanel(); 
TextBox pasteTextBox = new TextBox(); 
Menu stackPanelMenu = new Menu(); 
MenuItem pasteMenuItem = new MenuItem(); 
// Aggiunta oggetti al pannello e al menu
stackPanelMenu.Items.Add(pasteMenuItem); 
mainStackPanel.Children.Add(stackPanelMenu); 
mainStackPanel.Children.Add(pasteTextBox); 
// Inizializza il comando al valore Incolla
pasteMenuItem.Command = ApplicationCommands.Paste;

 

I Quattro Concetti Essenziali nel Sistema dei Comandi di WPF

Il modello di comando pilotato di WPF può essere suddiviso in quattro concetti essenziali: il comando, la sorgente del comando, il destinatario del comando [target: obiettivo n.d.t.] e il collegamento del comando [command binding n.d.t.]. Il comando è l'azione che deve essere eseguita. La sorgente del comando è l'oggetto che invoca il comando. Il destinatario del comando è l'oggetto sul quale il comando viene eseguito. Infine, il collegamento del comando è l'oggetto che mappa la logica di comando sul comando.

Nell'esempio sopra riportato, Incolla è il comando, MenuItem è la sorgente del comando, TextBox è il destinatario del comando e il collegamento del comando è fornito dal controllo della TextBox. Esso non ha valore poiché non sempre il ComandBinding è fornito dal controllo. Abbastanza spesso il CommandBinding deve essere generato dallo sviluppatore dell'applicazione e potrebbe essere collegato ad un antenato [ancestor n.d.t.] del destinatario di comando. [Antenato inteso come classe padre, nonno, bisnonno nella catena di ereditarietà di OOP n.d.r.]

Comandi

In WPF i comandi sono generati implementando l'interfaccia di ICommand. L'ICommand espone due metodi e un evento: Execute, CanExecute e CanExecuteChanged. Execute esegue l'azione del comando, CanExecute stabilisce se il comando può essere eseguito sul corrente destinatario di comando e CanExecuteChanged indica che la capacità di esecuzione del comando potrebbe essere cambiata. L'implementazione di WPF dell' ICommand è la classe RoutedCommand ed è il punto focale di questa panoramica.

Le principali sorgenti di input in WPF sono il mouse, la tastiera, l'ink [Ink provider di un Tablet PC o un Palmare con touch screen n.d.r.] e i comandi pilotati. Tutti questi tipi di input utilizzano un RoutedEvent per notificare agli oggetti che siè verificato un evento di input. Un RoutedCommand non è diverso. I metodi di Execute e di CanExecute di un RoutedCommand non contengono la logica di applicazione del comando, ma piuttosto essi invocano eventi pilotati i quali discendono [tunnel n.d.t.] e risalgono [bubble n.d.t.] attraverso l'albero degli elementi fino a quando incontrano un oggetto che implementa un CommandBinding. Il CommandBinding contiene i gestori di questi eventi e sono questi ultimi che eseguono il comando. Per maggiori informazioni sugli eventi pilotati in WPF, vedi Panoramica degli Eventi Pilotati  Routed events overview Panoramica degli Eventi Pilotati.

Il metodo Execute di un RoutedCommand invoca gli eventi di PreviewExecuted e di Excuted sul destinatario del comando. Il metodo CanExecute di un RoutedCommand invoca gli eventi di CanExecute e di PreviewCanExecute sul destinatario del comando. Questi eventi discendono [tunnel n.d.t.] e risalgono [bubble n.d.t.] attraverso l'albero degli elementi fino a quando incontrano un oggetto che possiede un CommandBinding per quel particolare comando.
WPF fornisce un insieme dei più frequenti comandi pilotati diffusi in numerose classi: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands e EditingCommands. In queste classi sono implementati esclusivamente gli oggetti del RoutedCommand, non la logica di funzionamento del comando, la quale deve essere implementata a cura dell'oggetto sul quale il comando viene eseguito.

 

 

Sorgenti di Comando (Command Sources)

 

Una sorgente di comando è l'oggetto che invoca il comando. Esempi di sorgenti di comando sono: MenuItem, Button e KeyGesture [Tasto funzione o shortcut n.d.r.].

Le sorgenti di comando in WPF generalmente implementano l'interfaccia di ICommandSource.

ICommandSource espone tre proprietà: Command, CommandTarget e CommandParameter. Command è il comando che viene eseguito quando la sorgente di comando è invocata. CommandTarget è l'oggetto sul quale si esegue il comando. Esso non ha valore poiché in WPF la property di CommandTarget su ICommandSource è applicabile solamente quando la ICommand è un RoutedCommand. Se il CommandTarget è impostato su una ICommandSource ed il corrispondente comando non è un RoutedCommand, il destinatario del comando viene ignorato. Se il CommandTarget non è impostato, l'elemento che ha il focus di tastiera [keyboard focus n.d.t.] sarà il destinatario del comando. Il CommandParameter è un tipo di dati definiti dall'utente utilizzati per passare informazioni ai gestori che implementano il comando.
Le classi di WPF che implementano la ICommandSource sono: ButtonBase, MenuItem, Hyperlink e InputBinding. ButtonBase, MenuItem e Hyperlink invocano un comando quando vengono cliccati, InputBinding evoca un comando quando l' InputGesture con il quale è associato(associated:unito,collegato) viene eseguito.
L'esempio seguente indica come utilizzare, in un ContextMenu, un MenuItem come sorgente di comando per il comando Properties.

XAML

<StackPanel> 
	   <StackPanel.ContextMenu> 
	      <ContextMenu> 
	         <MenuItem Command="ApplicationCommands.Properties" />
	      ContextMenu> 
	   StackPanel.ContextMenu> 
	StackPanel>

C#

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;

 

Generalmente una sorgente di comando sarà in ascolto dell'evento CanExecuteChanged. Questo evento informa la sorgente di comando che la capacità di esecuzione del comando sul corrente destinatario [target del comando n.d.t.] potrebbe essere cambiata. La sorgente di comando può interrogare lo stato corrente del RoutedCommand servendosi del metodo CanExecute. Nel caso in cui il comando non possa procedere nell'esecuzione, la sorgente di comando può disattivarsi [disable n.d.t.]. Un esempio di questo si ha quando un MenuItem si rende grigio [si disattiva n.d.r.] poichè non può procedere nell'esecuzione.
Un InputGesture può essere utilizzato come sorgente di comando. In WPF sono presenti due tipi di movimenti di input [input gestures:gesti, atti n.d.t]: il KeyGesture e il MouseGesture.
Potete considerare KeyGesture come uno shortcut di tastiera [keyboard shortcut n.d.t.], per esempio Ctrl-C. Un KeyGesture è costituito da un tasto e da un insieme di ModifierKeys [Ctrl,Shift,Alt n.d.r.].
Un MouseGesture è costituito da una MouseAction e da un insieme facoltativo di ModifierKeys.
Affinchè un InputGesture agisca come una sorgente di comando, deve essere associato ad un comando. Una delle poche possibilità per realizzare questo, consiste nel servirsi di un InputBinding. L'esempio seguente dimostra come generare un KeyBinding tra un KeyGesture e un RoutedCommand.

XAML

<Window.InputBindings>
	   <KeyBinding Key="B" Modifiers="Control" 
	      Command="ApplicationCommands.Open" /> 
	Window.InputBindings>

C#

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 InputGesture ad un RoutedCommand è quello di aggiungere l'InputGesture alla InputGestureCollection su un RoutedCommand. L'esempio seguente indica come aggiungere una KeyGesture all InputGesture di un RoutedCommand.

C#

KeyGesture OpenCmdKeyGesture = new KeyGesture( 
	    Key.B, ModifierKeys.Control); 
	ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);

 

Comand Binding (Collegamento dei comandi)

Un CommandBinding associa un comando ai gestori d'evento che implementano il comando. La classe CommandBinding è composta da una property Command e dagli eventi PreviewExecuted, Executed, PreviewCanExecuted e CanExecute.
Command è il comando al quale il CommandBinding viene associato. I gestori d'evento che sono collegati agli eventi PreviewExecute e Executed implementano la logica del comando. I gestori d'evento che sono collegati agli eventi PreviewCanExecute e CanExecute stabiliscono se il comando può effettuare l'esecuzione sul corrente destinatario del comando. L'esempio seguente indica come generare un CommandBinding sulla  Window Root di una applicazione. Il CommandBinding associa il comando Open ai gestori di Executed e  di CanExecute.

XAML

<Window.CommandBindings> 
	   <CommandBinding Command="ApplicationCommands.Open" 
	      Executed="OpenCmdExecuted" 
	      CanExecute="OpenCmdCanExecute"/> 
	Window.CommandBindings>

C#

// Creating CommandBinding and attaching an Executed and CanExecute handler 
	CommandBinding OpenCmdBinding = 
	   new CommandBinding( ApplicationCommands.Open, 
	      OpenCmdExecuted, OpenCmdCanExecute); 
	this.CommandBindings.Add(OpenCmdBinding);

In questo modo ExecutedRoutedEventHandler e CanExecuteRoutedEventHandler sono generati. Il ExecutedRoutedEventHandler apre un MessageBox che visualizza una stringa che riporta l'avvenuta esecuzione del comando. Il CanExecuteRoutedEventHandler imposta la property di CanExecute come Vera.

C#

void OpenCmdExecuted(object target, 
	   ExecutedRoutedEventArgs e) 
	{
	    MessageBox.Show("The command has been invoked."); 
	}

VB

Sub OpenCmdExecuted(ByVal sender As Object, _
	   ByVal e As ExecutedRoutedEventArgs) _
	   MessageBox.Show("The command has been invoked.") 
	End Sub

C#

void OpenCmdCanExecute(object sender, 
	    CanExecuteRoutedEventArgs e) 
	{ 
	   e.CanExecute = true; 
	}

VB

Sub OpenCmdCanExecute(ByVal sender As Object, _
	   ByVal e As CanExecuteRoutedEventArgs) 
	    e.CanExecute = True 
	End Sub

Un CommandBinding è collegato ad un oggetto specifico, come ad esempio alla Window Root di un'applicazione o di un controllo. L'oggetto al quale il CommandBinding è collegato determina il campo di visibilità [scope:campo, ambito n.d.t.] del collegamento [binding n.d.t.]. Ad esempio: un CommandBinding collegato ad un antenato[ancestor] del destinatario del comando può essere raggiunto dall'evento Executed. Se invece il CommandBinding è collegato ad un discendente del destinatario del comando non potrà essere raggiunto. Questo ha una diretta conseguenza sul modo in cui un RoutedEvent discende [tunnels n.d.t.] e risale [bubbles n.d.t.] lungo la porzione dell'albero di cui è parte l'oggetto che ha invocato l'evento.

In alcune situazioni il CommandBinding è collegato esso stesso ad un destinatario di comando, come per la classe TextBox e i comandi Cut, Copy e Paste. Tuttavia, abbastanza spesso, è più conveniente collegare il CommandBinding ad un antenato [ancestor - lungo l'albero logico] del destinatario del comando, come ad esempio la Window principale o l'oggetto Application, specialmente se lo stesso ComandBinding viene utilizzato per molteplici destinatari di comando. Queste sono comunque decisioni in fase di progettazione, che prenderete in considerazione nel momento in cui creerete le vostre infrastrutture del sistema di comando.

 

 

Command Target (Destinatario del Comando)

 

Il destinatario del comando è l'elemento sul quale il comando viene eseguito. Nei confronti di un RoutedCommand, il destinatario del comando è l'elemento per mezzo del quale viene avviato il routing di Executed e di CanExecute. Come osservato in precedenza, in WPF la property CommandTarget che si trova su ICommandSource è applicabile solamente quando il ICommand è un RoutedCommand. Se il CommandTarget è impostato su un ICommandSource e il corrispondente comando non è un RoutedCommand, il destinatario del comando verrà ignorato.
La sorgente del comando può esplicitamente impostare il destinatario del comando. Se esso non è definito, l'elemento che ha il focus di tastiera verrà utilizzato come destinatario del comando. Il beneficio ottenuto usando l'elemento che ha il focus come destinatario del comando, è che esso permette allo sviluppatore dell'applicazione di servirsi della stessa sorgente di comando per invocare un comando su molteplici destinatari senza dover mantenere traccia [to keep track of:non perdere di vista, seguire n.d.t.] del destinatario del comando. Ad esempio, se un MenuItem invoca il comando di incolla in un'applicazione che ha un controllo TextBox e un controllo PasswordBox, il destinatario può essere sia il TextBox che il PasswordBox a seconda di quale dei due controlli sia focalizzato. L'esempio seguente indica come impostare il destinatario del comando utilizzando il markup e relativo code behind.

XAML

	<StackPanel> 
	   <Menu> 
	      <MenuItem Command="ApplicationCommands.Paste" 
	         CommandTarget="{Binding ElementName=mainTextBox}" />
	   Menu> 
	<TextBox Name="mainTextBox"/>

C#

	// 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;

 

Command manager (Amministratore del Comando)

 

Il CommandManager è al servizio di numerose funzioni di comando collegate fra loro. Esso offre un'insieme di metodi statici per l'aggiunta e la rimozione dei gestori di evento PreviewExecuted, Executed, PreviewCanExecute e CanExecute allo scopo di fare un'intersezione logica [un AND n.d.r.] su elementi specifici. Inoltre procura il modo per registrare gli oggetti CommandBinding e InputBinding  nella classe specifica. Il CommandManager offre anche una modalità, tramite l'evento RequerySuggested, per notificare un comando nel momento in cui quest'ultimo dovrebbe sollevare l'evento CanExecuteChanged.
Il metodo InvalidateRequerySuggested obbliga il CommandManager a sollevare l'evento RequerySuggested. Ciò è utile nelle circostanze in cui un comando dovesse essere disabilitato/abilitato, ma non sono condizioni delle quali il CommandManager è consapevole. Per un esempio di chiamata da parte di InvalidateRequerySuggested al fine di costringere il CommandManager a sollevare l'evento RequerySuggested, vedi: Esempio di Disabilitazione della Sorgente del Comando Via Timer del Mittente Disable Command Source Via Dispatcher Timer Sample.

Libreria di Comando

WPF offre un insieme di comandi predefiniti. La libreria di comando è composta dalle seguenti classi: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommands e ComponentCommands.
Queste classi forniscono comandi come Cut, BrowseBack e BrowseForward, Play, Stop e Pause.
La maggior parte di questi comandi comprende un insieme di collegamenti dell'input di default. Ad esempio, se voi specificate che la vostra applicazione gestisce il comando di copia, ottenete automaticamente lo shortcut di tastiera "CTRL +C". Ottenete anche collegamenti per altri dispositivi di input, come i movimenti della penna del Tablet PC e informazioni vocali.

Generare Comandi Personalizzati

Se i comandi delle classi della Libreria di comando non soddisfano le vostre necessità, potete creare i vostri comandi. Ci sono due metodi per creare un comando personalizzato. Il primo è partire da zero e implementare l'interfaccia ICommand. Il secondo metodo, il più utilizzato come approccio, è creare un RoutedCommand od un RoutedUICommand.

Come esempio di generazione di un RoutedCommand personalizzato, vedi Esempio di Generazione di un RoutedCommand Personalizzato Create a Custom RoutedCommand Sample.

© 2007 Microsoft Corporation
Trademark information is available at http://www.microsoft.com/library/toolbar/3.0/trademarks/en-us.mspx

Traduzione a cura di Patrizia Cosolo, Revisione tecnica a cura di Sabrina Cosolo.



       
Articoli|Webcast|Risorse|Utility
© 2007-2010 by DotNetWork  .:.  Terms Of Use  .:.  Privacy Statement  .:.  Login  .:.