Introduction
Silverlight 4 now came up with the support of Command Binding. Using Command Binding, you can easily develop your Silverlight MVVM (Model-View-ViewModel) applications where your view will not know about the data, i.e., a full separation of the view from the model. In this article, I will describe how to implement the command binding to load some information & display it to the UI.
Background
In the earlier version of Silverlight, if you wanted to load something on the click of a button, you had to register the event in your view and then you had to call the appropriate method to load data. Let's say, as an example I want to load the customer information of my grocery shop when I click on a specific button. How will you implement this in Silverlight? The answer is simple. I will register a Click event of the button and then I will call the CustomerProvider
to load the customer information in my view. It’s simple enough but do you agree that this scatters your view with the functionality to load the information? Yup, these backend related calls are tightly coupled with your view. They know each other and if I want to give the same call from a different button, I have to register the click event for that button and then have to give a call. It looks a bit ugly in normal scenarios.
Now assume the MVVM architecture, where you will have the view to show the UI related stuffs, model as data and viewmodel to do my necessary stuff to call the provider to get the customer information and store within the viewmodel. Your view will not have any information about your data. Once binded to the UI, it will automatically load the information. This will give you clean, maintainable code with separation of the view from the business logic.
Implementation of DelegateCommand
To implement Command binding, you have to create a DelegateCommand
which implements the ICommand
interface. The ICommand
interface is available in System.Windows.Input
namespace in the System.Windows.dll assembly. It defines the contract for commanding.
- It has an
EventHandler
“CanExecuteChanged
” which occurs when changes occur that affect whether the command should execute.
- It has a method named “
CanExecute
” and returns a boolean value true
or false
based on whether the command can be executed in its current state.
- Another method named “
Execute
” which is called when the command is invoked.
Here is the implementation of the ICommand
interface:
namespace System.Windows.Input
{
public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}
}
Now we have to implement the methods defined in the ICommand
interface to our DelegateCommand
class. Here is the simple implementation of the same:
using System;
using System.Windows.Input;
namespace Silverlight4.CommandBinding.Demo.CommandBase
{
public class DelegateCommand : ICommand
{
public event EventHandler CanExecuteChanged;
Func<object, bool> canExecute;
Action<object> executeAction;
bool canExecuteCache;
public DelegateCommand(Action<object> executeAction,
Func<object, bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
bool tempCanExecute = canExecute(parameter);
if (canExecuteCache != tempCanExecute)
{
canExecuteCache = tempCanExecute;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
return canExecuteCache;
}
public void Execute(object parameter)
{
executeAction(parameter);
}
#endregion
}
}
Implementation of ViewModelBase
Let us now implement the ViewModelBase
for our application. Though for this sample application you can directly use the ViewModel
, it is recommended to create a base class implementation by inheriting the INotifyPropertyChanged
interface so that if you are creating multiple ViewModel
s, it will be easier to inherit the base class. Here is the code for that:
using System.ComponentModel;
namespace Silverlight4.CommandBinding.Demo.CommandBase
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Implementation of ViewModel
Now all the base classes are ready to use. Hence, we can go further to create our first ViewModel
. In this example, we are going to load Customer
information, so we will name it as CustomerViewModel
.
First of all, we will create a new instance of DelegateCommand
“LoadCustomersCommand
” which is an ICommand
type variable. It takes two parameters. The first one is the Action which fires when the command executes and the second one is a Function pointer which returns whether the command can be executed. If it returns true
, the command binded to the element will be enabled to do the operation and if it returns false
, the command binded to the element will be disabled by default. Once it becomes true
by any other operation, the UI thread automatically makes the element enabled.
Here in the demo application when the command executes, we will fetch the customer information from the provider and store the data in the ObservableCollection
called “CustomerCollection
”. We used ObservableCollection
because it inherits the INotifyPropertyChanged
interface and causes the UI thread to update the UI automatically when the collection changed event occurs binded to the specific UI.
public CustomerViewModel()
{
LoadCustomersCommand = new DelegateCommand(LoadCustomers, CanLoadCustomers);
}
private void LoadCustomers(object parameter)
{
CustomerCollection = CustomerProvider.LoadCustomers();
}
private bool CanLoadCustomers(object parameter)
{
return true;
}
Implementation of UI (XAML)
As of now, our back end code implementation is ready and now we have to create our UI to show the customer information. First of all, we will create the static
instance of the viewmodel
as a resource of the UserControl
. We named it as “vmCustomer
”. Now we will design our UI with a ListBox
and a Button
. Once we click on the button, it should execute the command and load the data in the ListBox
.
The ListBox
should point its ItemSource
to the CustomerCollection
inside the ViewModel
. The button will have the LoadCustomersCommand
associated with it. If the canExecute
method returns false
, you will notice the button as disabled and when it returns true
, it will become enabled.
Here is the full XAML implementation:
<UserControl x:Class="Silverlight4.CommandBinding.Demo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Silverlight4.CommandBinding.Demo.ViewModel"
Width="500" Height="300">
<UserControl.Resources>
<local:CustomerViewModel x:Key="vmCustomer"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Border CornerRadius="10,10,0,0" Background="Black"
Height="30" VerticalAlignment="Top" Margin="20,20,20,0">
<TextBlock Text="Silverlight 4 Command Binding Demo" Foreground="White"
FontWeight="Bold" Margin="5"/>
</Border>
<ListBox ItemsSource="{Binding CustomerCollection,
Source={StaticResource vmCustomer}}"
Margin="20,50,20,40">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Name}"
Width="100" Grid.Column="0"/>
<TextBlock Text="{Binding Path=Address}"
Width="200" Grid.Column="1"/>
<TextBlock Text="{Binding Path=ContactNumber}"
Width="100" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Command="{Binding LoadCustomersCommand,
Source={StaticResource vmCustomer}}"
Content="Load Customers" Height="25" Margin="380,267,20,8" />
</Grid>
</UserControl>
What’s Next?
Our full code implementation is ready. We can now run the application to see the code to execute. Press F5 to run it. Once the view is loaded, you will see the ListBox
is empty and there is a button just below the empty ListBox
.
Now press the button. It will fire the command to the viewmodel
and will fetch the customer information from the provider to load it in the collection. Once the collection is modified, this will automatically trigger the PropertyChanged
event to update the UI.
Conclusion
You will notice that in the entire sample, we didn’t write any code in the CS file of the XAML, i.e., the MainPage.xaml.cs is empty. This ensures that the business logic is totally separated from the UI implementation. This gives higher readability and maintainability of the code.
You are welcome to make any queries, comments or suggestions here. Also, don’t forget to vote for it.