Analizzando diverse soluzioni WPF che sfruttano l’architettura M-V-VM, mi è saltata all’occhio una strategia di implementazione dell’interfaccia ICommand semplice e potente a mio modo di vedere. Andiamo direttamente al codice:
public class GenericCommand<T> : ICommand
{
public Predicate<T> CanExecuteDelegate { get; set; }
public Action<T> ExecuteDelegate { get; set; }
public bool CanExecute(object parameter)
{
if (CanExecuteDelegate != null) return CanExecuteDelegate((T)parameter);
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (ExecuteDelegate != null) ExecuteDelegate((T)parameter);
}
}
Sostanzialmente l’obiettivo di questo GenericCommand è di permettere una “tipizzazione” dichiarativa del parametro gestito dall’ interfaccia ICommand, in modo tale da poter costruire ViewModel contenenti delegati che gestiscono il pattern CanExecute/Execute operando a nostro piacimento su parametri tipizzati passati magari direttamente dalla View. Ecco un esempio molto semplice di ViewModel...
public class ContactsViewModel
{
public ObservableCollection<string> Contacts { get; private set; }
public GenericCommand<string> AddContact { get; set; }
public GenericCommand<object> ClearContacts { get; set; }
public ContactsViewModel()
{
Contacts = new ObservableCollection<string>();
AddContact = new GenericCommand<string>();
ClearContacts = new GenericCommand<object>();
AddContact.CanExecuteDelegate += new Predicate<string>(AddContact_CanExecute);
AddContact.ExecuteDelegate += new Action<string>(AddContact_Execute);
ClearContacts.CanExecuteDelegate += new Predicate<object>(ClearContacts_CanExecute);
ClearContacts.ExecuteDelegate += new Action<object>(ClearContacts_Execute);
}
bool AddContact_CanExecute(string contactName) { return (!string.IsNullOrEmpty(contactName)); }
void AddContact_Execute(string contactName) { Contacts.Add(contactName); }
bool ClearContacts_CanExecute(object parameter) { return (Contacts.Count > 0); }
void ClearContacts_Execute(object parameter) { Contacts.Clear(); }
}
...e per chiudere il cerchio riporto anche lo XAML saliente di una View di esempio.
<TextBox Name="txtContactName" ... />
<Button Command="{Binding AddContact}" CommandParameter="{Binding ElementName=txtContactName, Path=Text}" ...>Add Contact</Button>
<ListBox ItemsSource="{Binding Contacts}" ... />
<Button Command="{Binding ClearContacts}" ...>Clear Contacts</Button>
Cosa ne pensate?
Technorati Tag:
WPF,
ICommand,
M-V-VM