In the NetAdvantage WebClient: Silverlight March CTP an interesting, but somewhat hidden feature is the new Commanding framework that we have built. The framework is based heavily on the WPF commanding framework, and can allow you to more easily implement Silverlight applications using the popular MVVM (Model-View-ViewModel) pattern. This article shows you how you can use the Commanding framework to create and use your own custom commands.
The basic premise of a Command is to give you a way to decouple UI events from the functionality you want them to execute. For example, common functionality such as Open and Save, or Cut, Copy and Paste are great candidates for Commands because this type of code would normally be tightly tied to specific UI events, which would be sprinkled throughout your application. Commands allow you to centralize the code for this type of functionality, and a Commanding framework provides you with a unified mechanism for attaching Commands to UI events in a highly decoupled (and testable) manner.
The Infragistics commanding framework is made if of three basic parts, a Command, which contains the actual feature logic (such as saving data), a Command Target, which allows you designate objects as targets of specific commands, as well as provide parameters to commands, and the Command Source, which is the glue that holds the Command and Target together.
To get started creating my own custom Command, all I have to do is create a new Silverlight class that derives from the Infragistics.Silverlight.CommandBase class. For purposes of this article, I am going to create a command called SaveCommand, which could use be used save some data in my application.
If you are familiar with WPF, the CommandBase class should look fairly familiar to you, exposing two methods I need to override in my derived class, CanExecute and Execute.
public class SaveCommand : Infragistics.Silverlight.CommandBase { public override bool CanExecute(object parameter) { return true; } public override void Execute(object parameter) { //Add Save code here HtmlPage.Window.Alert("Save Menu Clicked"); } }
The CanExecute method returns a Boolean value that indicates whether or not the command can be executed given the current state of the application. When a command is run, it first runs the CanExecute method which gives me an opportunity to check the current state of the application and determine of the command should be allowed to be run. If False is returned from CanExecute, then the UI element associated with this command will be disabled.
The Execute method is where I put the code I actually want executed by the Command. In this case, I am simply showing a JavaScript alert, but I could just as easily put code in here to save data to Isolated Storage, or send it to a remote server via a web service.
Next, I need to designate some object in my application as the target of the command. Designating an object as a command target allows the Commanding framework to locate this object at runtime, and also allows me the explicitly define what commands and object will support.
To designate an object as a command target, I implement the ICommandTarget interface on it. In my sample application I have several options for command targets. I could derive my own Button control that implements the interface and use that in the XamWebMenuItem template, I could derive my own menu control that implements the interface, or as I will for this sample, simply implement the interface on my user control.
public partial class MainPage : UserControl, ICommandTarget { public MainPage() { InitializeComponent(); } #region ICommandTarget Members public object GetParameter(CommandSource source) { return source; } public bool SupportsCommand(ICommand command) { return true; } #endregion }
The ICommandTarget requires two methods, GetParameter and SupportsCommand. The SupportsCommand method lets me specify the specific Commands that this target supports. In this case I have configured the UserControl to support any Command by simply returning true from the method. The GetParameter method allows the target to pass parameters to the Command before it is executed.
The last part of the Command I need to create is a Command Source. The Command Source is object that connects the Command and the Command Target, and is what I use to actually wire up the command to a specific user action in my applications XAML. To create the Command Source, all I need to do is create a new class that derived from Infragistics.Silverlight.CommandSource.
public class SaveCommandSource : Infragistics.Silverlight.CommandSource { protected override ICommand ResolveCommand() { return new SaveCommand(); } }
In this class, I override the ResolveCommand method and return an new instance of the command I want to execute. The ResolveCommand method gives you the opportunity to use your own application logic to determine what command should be instantiated. For example. if you look at the default template for the XamWebGrid and find the section of the template where the column headers sort indicator is defined, you will see that there is a single command source defined. This one command source can return a variety of Sorting related commands, based on the CommandType parameter passed into it.
Now that I have created all of the individual pieces of my Save Command, all I have to do is wire them all together. To do this, I am going to use the XamWebMenu control and invoke the Command when a menu item is clicked.
To indicate that I want the command to be invoked when I click the menu item, all I have to do is add a bit of XAML to the XamWebMenuItem:
<igmenu:XamWebMenu x:Name="XamWebMenu1"> <igmenu:XamWebMenuItem Header="File"> <igmenu:XamWebMenuItem Header="Save"> <ig:Commanding.Command> <cmd:SaveCommandSource EventName="Click" /> </ig:Commanding.Command> </igmenu:XamWebMenuItem> </igmenu:XamWebMenuItem> </igmenu:XamWebMenu>
Using the Commanding.Command attached property on the menu item, I assign my SaveCommandSource object as the command to execute. Within the SaveCommandSource object, I use the EventName property tell the Command Source what event of the menu item I want it to execute the command which can be any event that is exposed by the attached object. At runtime, the Command will automatically attach itself to the event specified. .
That's all it takes to create and use your own custom commands using the Infragistics Commanding framework. Now when I run my app, clicking on the Save menu item results in an alert being shown:
Now that I have everything wired together, lets review what's happening when I invoke the command.
When the application starts, the CommandSource automatically attaches to the event I have specified, in this case the XamWebMenuItems click event. When the menu item is clicked, the Commanding framework creates a new instance of the Command. It then attempts to resolve a Command Target. It does this in three different steps:
Once it finds a CommandTarget that supports the Command, it attempts to execute the command, first by checking the CanExecute method, then if CanExecute is true, running the Execute method.