Gestire il doppio-click Con Silverlight 4 e MVVM
Grazie al buon Ale forse ho raggiunto una soluzione intelligente e che mi piace. Lo scopo era quello di gestire il doppio-click all’interno di un’applicazione Silverlight 4 senza troppi fronzoli, e potendo sfruttare il tutto in un’ottica Model-View-ViewModel, quindi senza alcun codice nel code-behind delle Page.
Il tutto parte da questo post, segnalatomi questa mattina da Alessandro, appunto. 🙂
Il codice del post implementa un DoubleClickTrigger, da inserire poi come child di un qualsiasi componente grafico della nostra pagina, come StackPanel, TextBlock e così via. Voglio solo riproporre qui solo una parte del codice di quell’articolo, ovvero il gestore dell’evento OnMouseButtonDown:
private void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
{
if (!timer.IsEnabled)
{
timer.Start();
return;
}
timer.Stop();
// Qui si scatena il doppio-click, eseguo quello che devo eseguire
}
E’ piuttosto semplice: al primo MouseDown parte un piccolo Timer da 200ms. Se l’utente clicca nuovamente entro questo tempo, significa che è avvenuto un DoubleClick, e quindi raggiungiamo la riga di codice che qui sopra vedete commentata. Se mettessimo una MessageBox.Show(“”);, a tutti gli effetti sul doppio-click appare il vostro messaggio.
In un’ottica M-V-VM, però, sappiamo benissimo che tutto ciò che deve essere eseguito deve essere contenuto nella nostra classe ViewModel. La soluzione in questo caso è usare una attached-property, che permette di attaccare ad un componente grafico una qualsiasi istanza di ICommand, anche dove solitamente non sarebbe possibile. Ed ecco quindi poche righe di codice che lo rendono possibile:
public static class ControlsCommandHelper
{
public static DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command",
typeof(ICommand),
typeof(ControlsCommandHelper),
new PropertyMetadata(null));
public static void SetCommand(DependencyObject target, ICommand value)
{
target.SetValue(ControlsCommandHelper.CommandProperty, value);
}
public static ICommand GetCommand(DependencyObject target)
{
return (ICommand)target.GetValue(CommandProperty);
}
}
A questo punto l’event handler sopra diventa:
private void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
{
if (!timer.IsEnabled)
{
timer.Start();
return;
}
timer.Stop();
UIElement element = sender as UIElement;
if (element != null)
{
ICommand command = element.GetValue(ControlsCommandHelper.CommandProperty) as ICommand;
if (command != null)
{
command.Execute(null);
}
}
}
Morale: quando avviene un DoubleClick, prendo lo UIElement che ha scatenato l’evento, recupero la sua attached property Command e – se tutto va a buon fine – semplicemente eseguo il comando. In questo caso passo null all’Execute(), altrimenti dovrei gestire anche il CommandParameter.
Quindi, niente code-behind. Il tutto può essere inserito, come dicevo all’inizio, anche all’interno di un DataTemplate di una ListBox, quindi questa tecnica può essere benissimo utilizzata per reagire al doppio-click, lavorando sul SelectedItem della ListBox stessa.
Rimane solo il problema dei 200ms, che non mi piacciono perchè dovrebbe essere l’OS che si prende cura di dirmi quando è avvenuto un doppio-click. Anche perchè un utente può andare nel pannello di controllo e allungare/diminuire il tempo considerato per il doppio-click, e così facendo lo ignoro e basta.
Ecco comunque un piccolo codice sorgente che può essere utile.