Silverlight 4 - Make Commanding use lesser code
In my previous post about using Silverlight 4 Commanding, I got a question why I didn’t use delegates etc instead of creating a lot of ICommand classes. In this post I’m going to show how you can reduce the number of ICommand classes.
I have created a class with the name Command, this class implements the ICommand interface and uses two constructor arguments of a delegate type, in this case the Predicate<T> and Action<T>. I use the Predicate<T> for the ICommand.CanExecute because it takes one argument and returns a bool (I could have used the Func<T, TResult>), and I use the Action<T> for the ICommand.Execute, Action<T> doesn’t return anything and takes one argument.
Here is the implementation of the Command class:
public class Command : ICommand { public event EventHandler CanExecuteChanged; Predicate<Object> _canExecute = null; Action<Object> _executeAction = null; public Command(Predicate<Object> canExecute, Action<object> executeAction) { _canExecute = canExecute; _executeAction = executeAction; } public bool CanExecute(object parameter) { if (_canExecute != null) return _canExecute(parameter); return true; } public void UpdateCanExecuteState() { if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter) { if (_executeAction != null) _executeAction(parameter);
UpdateCanExecuteState(); } }
Because the ICommand’s CanExecute and Execute method takes one argument of type ojbect (the value comes from the ButtonBase class’s CommandParamter) I decided to still use it, so the T in Preditcate<T> and Actiton<T> is of type object. In this example I also added the code to trigger the CanExecuteChanged event after the Execute is done. The reason I did that was because the CanExecute can be based on the result of the Execute. You can trigger the CanExecuteChanged event when you want the UI to check the CanExecute method. The CanExecute will normally take place when the UI is loaded, and before the Execute method is executed.
To specify a Command in a ViewModel with the Command class I only need to return an instance of the Command where I pass two lambda expressions to the constructor. Here is an example:
public class CommandingViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _myTextBox; private Command _saveCommand = null; public string MyTextBox { get { return _myTextBox; } set { if (_myTextBox != value) { _myTextBox = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("MyTextBox")); } } } public ICommand SaveCommand { get {
if(_saveCommand == null) _saveCommand = new Command ( p => string.IsNullOrEmpty(MyTextBox), p => MyTextBox = "Save Button Pressed" );
return _saveCommand; } } }
The first lambda expression passed to the first argument of the Command class will return true or false to enable or disable for example a Button where the Command is used. The second lambda expression is the code that will be executed when the Button is pressed (when the Command is executed). The “p” in the expressions will hold the CommandParameter result. Here is the View I used for the example above:
<UserControl xmlns:view="clr-namespace:Commanding.ViewModel" ...> <UserControl.Resources> <view:CommandingViewModel x:Name="myView"/> </UserControl.Resources> <Grid x:Name="LayoutRoot" DataContext="{StaticResource myView}"> <StackPanel VerticalAlignment="Center"> <TextBox Height="50" Width="200" Text="{Binding MyTextBox}"/> <Button Content="Save" Height="50" Width="100" CommandParameter="1" Command="{Binding SaveCommand}"/> </StackPanel> </Grid> </UserControl>
As you can see, with a solution where we pass a lambda expression, we can reduce the number classes used and also make sure the Command code stays within the ViewModel.
If you want to know when I publish new blog posts, then you can follow me on twitter: http://www.twitter.com/fredrikn