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