Passa ai contenuti principali

Appunti di WPF – Quattordicesima Puntata – Comandi

WPF mette a disposizione una infrastruttura per la gestione dei comandi (cioè delle funzionalità che stanno dietro i controlli di una finestra applicativa) decisamente più evoluta rispetto a quella presente nelle Windows Forms in cui tale gestione è demandata ad un utilizzo oculato dei gestori di eventi.

In una applicazione ben progettata, il task applicativo che sta dietro ad un comando, non dovrebbe essere direttamente eseguito all’interno di un gestore di evento ma  in maniera disgiunta da questo.

Il comando applicativo, quindi, dovrebbe essere astratto rispetto al gestore di evento che lo gestisce in modo che sia molto facile fornire agli utenti nuovi controlli che eseguono lo stesso task.

Il modello dei comandi di WPF è composto dai seguenti pilastri:

· Commands : un comando rappresenta un task applicativo e contiene le informazioni necessarie per conoscere quando tale comando può essere eseguito o meno. Un comando non contiene il task vero e proprio (che, di solito, è contenuto in una apposita classe);

· Command Bindings : il command binding lega il comando all’effettiva logica applicativa. Grazie al command binding un comando può essere utilizzato in differenti punti della nostra applicazione;

· Sources : sono i controlli che generano il comando (button, menu, etc., etc.);

· Targets : sono gli elementi per cui il comando viene eseguito. Ad esempio l’apertura della lista delle stampanti in un comando Print.

L’interfaccia ICommand (contenuta nel namespace System.Windows.Command) definisce il comportamento di un comando. Questa interfaccia definisce i seguenti metodi ed eventi:

  1. Public Interface ICommand
  2.     ' Events
  3.     Custom Event CanExecuteChanged As EventHandler
  4.  
  5.     ' Methods
  6.     Function CanExecute(ByVal parameter As Object) As Boolean
  7.     Sub Execute(ByVal parameter As Object)
  8. End Interface

Il metodo Execute() contiene il task da eseguire mentre il metodo CanExecute() viene richiamato dal framework quando lo stesso framework ha la necessità di conoscere se il comando può essere eseguito o meno. Infine, l’evento CanExecuteChanged() viene invocato quando lo stato del comando cambia.

Possiamo definire un nostro comando implementando l’interfaccia ICommand ma possiamo utilizzare la classe RoutedCommand che ci mette a disposizione una serie di metodi accessori (come, ad esempio, la gestione del bubbling del comando che permette al comando di navigare la gerarchia dei controlli WPF fino a trovare l’opportuno gestore) che semplificano la realizzazione del comando.

Altra classe fondamentale per la gestione dei comandi è la RoutedUICommand che deriva dalla RoutedCommand ma che fornisce la possibilità di definire un testo del comando (con eventuale localizzazione del testo).

WPF_14_Comandi_Fig1

Il framework WPF ci mette a disposizione una serie di comandi predefiniti (che troviamo nella maggior parte delle applicazioni Windows) e che possono essere utilizzati senza dover usare direttamente la classe RoutedUICommand. Per accedere a questi comandi possiamo utilizzare le classi ApplicationCommands (per i normali comandi quali Copy, Paste, Open, New, etc., etc.), NavigationCommands (per i comandi di navigazione), EditingCommand (per i comandi di edit dei documenti), ComponentCommands e MediaCommands.

Vediamo ora, come eseguire un comando.

Per prima cosa abbiamo bisogno è una sorgente, cioè un oggetto che implementa l’interfaccia ICommandSource.

L’interfaccia ICommandSource prevede i seguenti membri:

· Command : oggetto ICommand che l’ICommandSource deve eseguire;

· CommandParameter : permette di inviare un qualsiasi oggetto al comando;

· CommandTarget : oggetto da cui il comando è effettivamente eseguito.

Il terzo pilastro per la gestione dei comandi in WPF è il CommandBinding. Il command binding permette di legare il comando al controllo o ai controlli che lo eseguono.

Cominciamo a vedere un esempio di interfaccia XAML con l’utilizzo di un comando:

  1. <Window x:Class="MainWindow"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="MainWindow" Height="350" Width="525">
  5.     <Window.CommandBindings>
  6.         <CommandBinding Command="Print"
  7.             Executed="PrintCommand_Executed"
  8.             CanExecute="PrintCommand_CanExecute"></CommandBinding>
  9.     </Window.CommandBindings>
  10.     <Grid>
  11.         <Grid.RowDefinitions>
  12.             <RowDefinition Height="20" />
  13.             <RowDefinition Height="*" />
  14.             <RowDefinition Height="Auto" />
  15.         </Grid.RowDefinitions>
  16.         <Menu Grid.Row="0">
  17.             <MenuItem Command="Print" VerticalAlignment="Center"></MenuItem >
  18.         </Menu>
  19.         <StackPanel Grid.Row="2">
  20.             <Button Command="Print"
  21.                 Content="{Binding Path=Command.Name, RelativeSource={RelativeSource Self}}"></Button>
  22.         </StackPanel>
  23.     </Grid>
  24. </Window>

Se eseguiamo l’applicazione, osserviamo che i due controlli sono disabilitati:

WPF_14_Comandi_Fig2Questo perché il framework, quando deve capire qual è lo stato del comando esegue il metodo PrintCommand_CanExecuted che, in questo caso, restituisce il valore di default (che è quello dello stato non abilitato).

Per attivare il comando ci basta scrivere il seguente codice:

  1. Private Sub PrintCommand_CanExecute(ByVal sender As System.Object,
  2.                                     ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)
  3.     e.CanExecute = True
  4. End Sub
  5.  
  6. Private Sub PrintCommand_Executed(ByVal sender As System.Object,
  7.                                   ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)
  8.     MessageBox.Show("Print")
  9. End Sub

Il primo dei due gestori di evento comunica al framework che il comando è sempre attivo (e.CanExecute=true) mentre il secondo gestore esegue il comando.

Il risultato è il seguente:

WPF_14_Comandi_Fig3 In un’applicazione reale, lo stato del comando dipenderà dallo stato dell’applicazione.

I vantaggi sono notevoli: non dobbiamo implementare il codice che aggiorna lo stato dei controlli in base allo stato del comando, aggiungere nuovi controlli che eseguono lo stesso comando è una banalità e, infine, il task applicativo non è inserito nel gestore dell’evento dei controlli disaccoppiando il codice dall’interfaccia.

Inoltre, come possiamo osservare dal precedente XAML, anche il testo che appare nei controlli è standardizzato e un’eventuale localizzazione coinvolgerebbe tutti i controlli dello stesso comando in un colpo solo.

Il binding dei comandi si può eseguire anche da codice come mostrato di seguito:

  1. Dim binding = New CommandBinding(ApplicationCommands.Close)
  2. With binding
  3.     AddHandler .CanExecute, AddressOf Close_CanExecute
  4.     AddHandler .Executed, AddressOf Close_Executed
  5. End With

E’, possibile, inoltre eseguire un comando direttamente da codice utilizzando l’istruzione:

  1. ApplicationCommands.Print.Execute(Nothing, targetElement)

Esistono , infine, alcuni controlli che hanno già dei specifici comandi predefiniti. Un esempio di questo è il TextBox. Quando inseriamo il controllo TextBox in una pagina, abbiamo la possibilità di inserire dei comandi tipo Edit, Paste e Undo la cui attivazione è gestita direttamente dal framework in base al fatto che un utente selezioni del testo, abbia del testo nella clipboard o annulli l’ultima operazione. Ad esempio:

  1. <Window x:Class="Toolbar"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="Toolbar" Height="300" Width="300">
  5.     <Grid>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="Auto"></RowDefinition>
  8.             <RowDefinition Height="*"></RowDefinition>
  9.         </Grid.RowDefinitions>
  10.         <ToolBar>
  11.             <Button Command="Copy">Copy</Button>
  12.             <Button Command="Paste">Paste</Button>
  13.             <Button Command="Undo">Undo</Button>
  14.         </ToolBar>
  15.         <StackPanel Grid.Row="1" Margin="10">
  16.             <TextBox>
  17.                 <TextBox.Background>
  18.                     <RadialGradientBrush>
  19.                         <GradientStop Color="cyan" Offset="1"></GradientStop>
  20.                         <GradientStop Color="white" Offset="0"></GradientStop>
  21.                     </RadialGradientBrush>
  22.                 </TextBox.Background>
  23.             </TextBox>
  24.         </StackPanel>
  25.     </Grid>
  26. </Window>

WPF_14_Comandi_Fig4

Per finire questo tutorial vediamo come creare rapidamente un comando custom.

Supponiamo di voler implementare il comando di Export. Definiamo la seguente classe:

  1. Public Class ExportCommand
  2.  
  3.     Private Shared _Export As RoutedUICommand
  4.  
  5.     Shared Sub New()
  6.         Dim inputs As New InputGestureCollection()
  7.         inputs.Add(New KeyGesture(Key.E, ModifierKeys.Control, "Ctrl+E"))
  8.         _Export = New RoutedUICommand("Export", "Export", GetType(ExportCommand), inputs)
  9.     End Sub
  10.  
  11.     Public Shared ReadOnly Property Export As RoutedUICommand
  12.         Get
  13.             Return _Export
  14.         End Get
  15.     End Property
  16.  
  17. End Class

Per utilizzare questo comando è necessario importare il namespace della nostra applicazione e impostare l’apposito binding come mostrato nel seguente XAML:

  1. <Window x:Class="Export"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     xmlns:l="clr-namespace:WpfApplication"
  5.     Title="Export" Height="300" Width="300">
  6.     <Window.CommandBindings>
  7.         <CommandBinding Command="l:ExportCommand.Export"
  8.                         Executed="CommandBinding_Executed"
  9.                         CanExecute="CommandBinding_CanExecute"></CommandBinding>
  10.     </Window.CommandBindings>
  11.     <Grid>
  12.         <Button Command="l:ExportCommand.Export">Export</Button>
  13.     </Grid>
  14. </Window>


Scarica la versione PDF dell'articolo. Scarica la versione Amazon Kindle dell'articolo.

Commenti

Post popolari in questo blog

MVP Reconnect …… ovvero quando entri nella “famigghia” resti sempre nella “famigghia”!!!

Ma di che “famigghia” stiamo parlando!!!!

Fermi tutti, non si tratta di robe strane o sette segrete o affari malavitosi….stiamo parlando della grande famiglia dei Microsoft MVP.

Per chi non sapesse cosa sono i Microsoft MVP, vi consiglio di fare un giro sul sito ufficiale del programma (link), ma, volendolo spiegare in pochisime parole, si tratta di un riconoscimento che Microsoft da a persone che si distinguono per il loro impegno, aiutando gli altri ad ottenere il massimo grazie alle tecnologie Microsoft. Si tratta di persone, non dipendenti Microsoft, che mettono la loro passione, il loro tempo, la loro buona volontà per la divulgazione e la condivisione della conoscenza. Non necessariamente (come qualcuno erroneamente sostiene, evidentemente non conoscendo le basi del programma) si tratta di professionisti nel termine letterale del termine ma si tratta comunque di un gruppo di persone che sacrifica un pò del suo tempo (e, a volte, vi assicuro neanche pò!!!) per la sua passione.

Pe…

Template di progetto per sviluppare applicazioni WPF con Intel® RealSense™

E’ disponibile, nella gallery di Visual Studio, la prima versione del mio template di progetto per applicazioni WPF scritte in C# che permette di realizzare applicazioni con l’SDK di Intel® RealSense™.Il template si può scaricare direttamente all’interno Visual Studio utilizzando il tool “Extensions and Updates”oppure all’indirizzo https://visualstudiogallery.msdn.microsoft.com/1c36ecfd-8c00-4aee-b20c-a1726ab6424dIl template esegue le seguenti operazioni per voi:Aggiunge la reference all’assembly libpxcclr.cs.dll (nelle due distinte versioni per x86 e x64);Aggiunge lo script di post build per copiare la libreria libpxccpp2c.dll dalla cartella dell’SDK alla cartella bin del vostro progetto.Una volta creato il progetto dovete rimuovere la configurazione di compilazione AnyCPU (che non ha più senso) dalla vostra solution e sarete pronti per sviluppare con Intel® RealSense™.Ovviamente dovete installare l’SDK che potete scaricare all’indirizzo https://software.intel.com/en-us/intel-realsen…

Nuova versione del Band SDK

E’ di ieri l’annuncio del rilascio della nuova versione dell’SDK per il Microsoft Band.
Si tratta della versione 1.3.10417 (la precedente e, prima della serie, era la 1.3.10219 preview).
Maggiori informazioni, download dell’SDK per le tre piattaforme Windows Phone, iOS e Android all’indirizzo http://developer.microsoftband.com/.
Allo stesso indirizzo potrete trovare anche la documentazione.
Nei mesi scorsi mi sono gia’ occupato della precedente versione e questi sono i post che ne parlano:
Microsoft Band SDK Preview - First LookMicrosoft Band SDK Preview - ”Hello Band”Microsoft Band SDK Preview - Accesso ai sensoriMicrosoft Band SDK Preview - TileMicrosoft Band SDK Preview - NotificheMicrosoft Band SDK Preview - Personalizzazione
Gli argomenti trattati e il codice proposto dovrebbe, ad una prima lettura delle nuove funzionalita’ inserite, essere ancora valido e funzionante ma nei prossimi giorni prendero’ in esame tutti gli argomenti dei precedenti post e vedremo cosa cambia e cosa e’ …