Building a Reusable ICommand implementation for Windows Phone Mango MVVM apps
published on: 6/17/2011 | Views: N/A | Tags: Mango MVVM
by WindowsPhoneGeek
In this post I am going to talk about the ICommand interface that is available with Windows Phone 7.1 Mango. I will demonstrate how to implement a reusable ICommand implementation: DelegateCommand and how to use it when building a MVVM Mango application.
When talking about Commands I need to mention that generally a command has two functions:
- Performing a particular action: this is the main functionality of a command
- To determine the visual state of a particular UIElement: for example determine whether a Button is enabled or not.
DelegateCommand - a Reusable ICommand implementation
Implementing DelegateCommand: a reusable ICommand class which allows you to reuse the class every time when you need to use a command (usually in your view models).
The ICommand interface consists of the following:
The ICommand members have the following meaning:
-
The CanExecuteChanged event and the CanExecute method are used to determine the visual state of the control to which the command is set. They work like this: usually when a command is set to a control (a Button for example), the control calls the CanExecute method in order to determine its initial visual state. In the case of the Button, if the call to the CanExecute method returns false the button becomes disabled. The control also subscribes to the CanExecuteChanged event. When a the CanExecuteChanged event is fired, CanExecute is called again in order to determine if it needs to change its visual state.
-
Execute method is straight forward: the control calls it when some action needs to be performed; in the case of the Button - when it is pressed.
In our case DelegateCommand instances will be initialized with a delegate which points to a method that will be executed when Execude is called. There is a second constructor that can be used to also pass a delegate to a method that will be called when CanExecute is called on the command.
Here is how we will implement our DelegateCommand :
public class DelegateCommand : ICommand
{
Func<object, bool> canExecute;
Action<object> executeAction;
public DelegateCommand(Action<object> executeAction)
: this(executeAction, null)
{
}
public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
{
if (executeAction == null)
{
throw new ArgumentNullException("executeAction");
}
this.executeAction = executeAction;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
bool result = true;
Func<object, bool> canExecuteHandler = this.canExecute;
if (canExecuteHandler != null)
{
result = canExecuteHandler(parameter);
}
return result;
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void Execute(object parameter)
{
this.executeAction(parameter);
}
}
Sample Usage in a Windows Phone Mango MVVM application
To demonstrate the usage of DelegateCommand we will implements a basic Windows Phone 7.1 Mango application using the MVVM pattern. Basically we will have a View, ViewModel and Model.
Model
I will create a simple class called Person with one property of type string inside it:
public class Person
{
public string Name
{
get;
set;
}
}
View Model
This is the most important part where I will use the newly created DelegateCommand class. I will create a basic PersonViewModel which exposes a DataSource property of type ObservableCollection<Person> and a LoadDataCommand property of type ICommand:
public class PersonViewModel
{
private ObservableCollection<Person> personDataSource;
private ICommand loadDataCommand;
public PersonViewModel()
{
this.personDataSource = new ObservableCollection<Person>();
this.loadDataCommand = new DelegateCommand(this.LoadDataAction);
}
private void LoadDataAction(object p)
{
this.DataSource.Add(new Person() { Name = "John"});
this.DataSource.Add(new Person() { Name = "Kate"});
this.DataSource.Add(new Person() { Name = "Sam"});
}
public ICommand LoadDataCommand
{
get
{
return this.loadDataCommand;
}
}
public ObservableCollection<Person> DataSource
{
get
{
return this.personDataSource;
}
}
}
View
In this part I will add some UI and will connect it to the data through the ViewModel. First of all, I will have to set the DataContext of the view. To keep things simple, I will just set the DataContext to an instance of PersonViewModel in the view constructor:
public MainPage()
{
InitializeComponent();
// simple way to bind the view to the view model
this.DataContext = new PersonViewModel();
}
Next I will add the Command Binding to a sample button that will populate a ListBox with data:
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Button Content="LoadData" Command="{Binding LoadDataCommand}" />
<ListBox ItemsSource="{Binding DataSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
For more information about commands you can also take a look at the following MSDN documentation posts:
That was all about implementing a DelegateCommand in Windows Phone 7.1 Mango and using it in a MVVM application. Here is the full source code:
I hope that the post was helpful.
You can also follow us on Twitter @winphonegeek
Comments
Commanding
posted by: Peter K. on 6/17/2011 8:05:41 PM
Quite an interesting approach. Thanks for the sample code. Looking forward your next mango article..
vote up
posted by: Martin F. on 6/17/2011 8:09:41 PM
Vote up for this post.
What about CanExecute
posted by: Vince M on 6/18/2011 5:58:47 AM
This is the second article I have come across on this subject and in both cases the CanExcute method is essentially ignored or always returns true. I have tried both versions of DelegateCommand (subtle differences) and in neither case can I get my CanExecute handler to be evaluated more than once. There is often a number of variables that need evaluating - am I busy, is there an entry in multiple text boxes, etc. What am I missing?
What about CanExecute, 2
posted by: Vince M on 6/18/2011 7:18:01 AM
OK, I figured it out - any property change that impacts the CanExecute needs to call:
(MyCommand as DelegateCommand).RaiseCanExecuteChanged();
RE: What about CanExecute
posted by: winphonegeek on 6/18/2011 11:26:03 AM
Indeed, the idea is to manually raise the CanExecuteChanged event when you need to refresh the visual state. This is why the RaiseCanExecuteChanged method is public instead of protected.
Another, more "automatic" implementation would be to use the static CommandManager.RequerySuggested event like in the snippet bellow.
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Unfortunately, the CommandManager class is not available on Windows Phone, so we are left with the the "manual" approach for now.
Excellent Explanation of Concrete Implementation of ICommand
posted by: Mike Gold on 8/14/2011 7:28:07 AM
This is a cool implementation of the ICommand. I find myself using RelayCommand and RelayCommand
-Mike
Our Top Articles & Free books
- Our FREE e-book: "Windows Phone Toolkit In Depth" 2nd edition
- 400+ Windows Phone Development articles in our Article Index
- 21 WP7 Toolkit in Depth articles covering all controls
- 12 WP7 Coding4Fun Toolkit in Depth articles covering all controls
- Performance Tips when creating WP7 apps
- Creating a WP7 Custom Control in 7 Steps
- WP7 working with VisualStates: How to make a ToggleSwitch from CheckBox
- What makes a WP7 App successful
- Creating theme friendly UI in WP7 using OpacityMask
- Implementing Windows Phone 7 DataTemplateSelector and CustomDataTemplateSelector
- All about Splash Screens in WP7 – Creating animated Splash Screen
- Getting Started with Unit Testing in Silverlight for WP7
- WP7 WatermarkedTextBox custom control
Our Top Tips & Samples
- All about WP7 Isolated Storage series
- WP7 Dynamically Generating DataTemplate in code
- 5 tips for a successful WP7 Marketplace submission
- WP7: Navigating to a page in different assembly
- WP7 ContextMenu: answers to popular questions
- WP7 ListBox: answers to popular questions
- WP7 working with Images: Content vs Resource build action
- WP7 Element Binding samples
- WP7 working with XML: reading, filtering and databinding
- Drawing in WP7: #2 Drawing shapes with finger
- WP7 TextBox Light theme problems - the solution
- Changing the WP7 Panorama Background Image dynamically with Animation
