In the previous post we’ve seen how to setup a Windows Phone application to use Caliburn Micro as a MVVM Framework. We’ve seen also the first conventions used by the toolkit, to connect together a View with its ViewModel and to bind a property to a control’s property. In this post we’ll see how to connect a control to an action, so that when the user interacts with the control the action is executed.
Commands in Caliburn Micro
Usually to accomplish this task using MVVM Light or the standard XAML approach we use the Command property: we would define an object that implements the ICommand interface and define the operation that should be executed when it’s invoked. In the end, the object is connected with the Command property of a Button, for example, using binding. This approach is very repetitive, because we need to create an ICommand object for every operation while, in the end, what we really need is to define just the method that should be invoked. Caliburn Micro avoid this requirement by using, guess what, a naming convention, similar to the one we’ve seen to bind properties to a control. Basically, you just need to declare in your view model a method which name matches the name of the control.
For example, declare a Button like this:
<Button Content="Show name" x:Name="ShowNameAction" />
Then, in your code, you’ll have a method like the following one:
public void ShowNameAction() { MessageBox.Show("Clicked"); }
Now if you launch the application and you press on the button you’ll see the message on the screen. The magical naming convention did the trick again! And what if we need a property to set the content of the button and, at the same time, an action to be triggered when the button is clicked? In this case we have a conflict with the naming convention rule: we can’t have in the view model both a method and a property with the same name.
In this case, we need to use the long syntax, that uses the behaviors available in the System.Windows.Interactivity namespace. For this reason, we need to add to our XAML the following namespaces:
xmlns:i=”clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
xmlns:cal=”clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro”
Now you need to change the Button declaration like in the following sample:
<Button x:Name="ShowName"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="ShowNameAction" /> </i:EventTrigger> </i:Interaction.Triggers> </Button>
As a label for the button will be used a property called ShowName declared in the ViewModel; instead, the ShowNameAction method will be executed when the button is clicked. One advantage of using this syntax is that you are able to attach a method also to other events: by default, using the standard naming convention, a method is hooked with the default event of the control (in case of a Button, it’s the Click event). With this syntax, instead, it’s enough to change the EventName property of the EventTrigger with another one (for example, DoubleTap) to connect the method with that event.
Caliburn Micro provides also a short syntax to do the same:
<Button cal:Message.Attach="[Event Click] = [Action ShowName]" />
The syntax is very simple: by using the Message.Attach attached property we define first the event we want to hook (with the keyword Event followed by the name of the event), then the name of the method that should be executed (with the keyword Action followed by the name of the method). The pros of the long syntax is that is supported by Blend, but it’s more verbose; the short syntax is easier to remember and to use, but Blend doesn’t like it. It’s up to you which syntax to use: personally I don’t use Blend too much, so losing the ability to see and interact with the button in Blend is not a big deal for me.
Controlling the action
One of the most interesting features that is available in the command pattern is the CanExecute concept: every command can be controlled by the developer, so that he can enable or disable it according to a specific condition. The coolest thing is that the control that is bound with the command will automatically change his status according to this condition: if the command is disabled, for example, the button will be grayed and the user won’t be able to click on it.
Basically, the CanExecute action returns a boolean value, that determines if the command can be executed or not. Every time something changes, this action should be evaluated again. A classic example is a form, that shouldn’t be submitted until the user has filled all the required fields. By default, the submit button is disabled but, every time a field is filled by the user, the action should be evaluated again, because the status of the button can change.
Also in this case Caliburn Micro uses conventions to support this feature: you just need to create in your ViewModel a boolean property, with the same name of the method prefixed by the Can word. Here is how to extend the previous example, by adding a Checkbox in our page, which we’re going to bound to a boolean property. The button should be activated only when the checkbox is enabled.
Here is the XAML in the view:
<StackPanel> <Button x:Name="ShowName" Content="Click me" /> <CheckBox x:Name="IsEnabled" Content="IsEnabled" /> </StackPanel>
And here is the code in our ViewModel:
public class MainPageViewModel: PropertyChangedBase { private bool isEnabled; public bool IsEnabled { get { return isEnabled; } set { isEnabled = value; NotifyOfPropertyChange(() => IsEnabled); NotifyOfPropertyChange(() => CanShowName); } } public bool CanShowName { get { return IsEnabled; } } public void ShowName() { MessageBox.Show("Clicked"); } }
As you can see, other than defining the ShowName method (that is invoked when the ShowName button is clicked), we create a boolean property which name is CanShowName. In the end, we create a property called IsEnabled, that is connected to the checkbox in the view. This way, every time the checkbox is enabled, the IsEnabled property is set to true and the same happens for the CanShowName property. The only thing to highlight is that, every time we change the value of the IsEnabled property, we call the NotifyOfPropertyChange method not only on the property itself, but also on the CanShowName property. This way, every time the IsEnabled property changes, also the CanShowName property is evaluated again and the button’s status is changed according to the new value.
To be continued
In the next posts we’ll keep digging in using Caliburn Micro, to manage collections, tombstoning, messaging and navigation. For the moment, you can start playing with the sample project below to take a deeper look to what we’ve learned in this post.
The Caliburn Micro posts series
Hello, awesome content! THANKS! I’m learning caliburn and loving it so far.
I think you have a typo in this line:
public void ShowName()
{
MessageBox.Show(“Clicked”);
}
x:Name MUST match the method name.
Thanks for the awesome content!
Yes, you’re right, thanks for the notification! Fixed.
Hi Matteo,
Thank You for great content.
I have problem with Caliburn Micro latest version. I tried your above sample code & working great but when I updated the latest version 2.0.1. the app is crashing at below line in App.xaml.cs
” PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; ”
The version your sample having is : 1.5.2
Here is OneDrive link of code : http://1drv.ms/1sYiqTn
I’m aware of few changes in latest version like ` PhoneBootstrapper ` class is renamed to ‘ PhoneBootstrapperBase ‘. What I’m missing here.
Did you try to move the UserIdleDetectionMode setting in the Bootstrapper class, rather that in the App.xaml.cs one?