Caliburn Micro Part 3: More About Events and Parameters

So far in this Caliburn Micro tutorial series we have looked at how to get started with using Caliburn Micro in a WPF application, and how to link the view and the view-model together using data binding and events. In today’s tutorial, we will take a look at the more advanced ways of hooking up events and specifying event parameters. To experiment with these features, we will be further extending the application created in the previous two blog posts.

You may remember from the previous blog post that we hooked up events using the help of Caliburn Micro’s naming conventions. All we needed to do was set the name of a button in the view to be the same name as a method in the view-model. Then the Click event of the button will be automatically hooked up to call the appropriate method. Sometimes however you will need to explicitly hook up the events in order to provide event parameters or specify exactly which event you want to use. To do this, Caliburn Micro provides a long syntax and a short syntax. The advantage of the long syntax is its compatability with Microsoft Expression Blend. The short syntax is great if you’re not interested in using a designer and want to keep things short and sweet. Let’s start off with learning how to use the long syntax.

Long Syntax

The best way to begin is to modify the existing application to use the long syntax without changing the current behaviour. Open up AppView.xaml and include these 2 namespaces:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org"

Then, simply replace the repeat button with this:

<RepeatButton Content="Up" Margin="15" VerticalAlignment="Top">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <cal:ActionMessage MethodName="IncrementCount" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</RepeatButton>

Run the application now and you will see it looks and behaves just as it did before. What we have done here is used System.Windows.Interactivity triggers to hook up an event to a method. In the EventTrigger we can specify which event we want to listen to, and using the Caliburn Micro ActionMessage we can specify which method should be called. Using this approach you can include any number of event triggers to listen to other events on the same control. So you could listen to MouseEnter and MouseLeave to perform additional actions.

Next let’s look at event parameters. To demonstrate this, we will add another button that increments the count by 2. In AppViewModel.cs we need to modify the IncrementCount method to include an integer parameter. This parameter will be used to change the Count property. The IncrementCount method will now look like this:

public void IncrementCount(int delta)
{
  Count += delta;
}

Back in AppView.xaml, update the existing repeat button by adding a Caliburn Micro Parameter to the ActionMessage like this:

<cal:ActionMessage MethodName="IncrementCount">
  <cal:Parameter Value="1" />
</cal:ActionMessage>

Now when the button is pressed, it will pass a value of 1 as a parameter to the IncrementCount method. Add another button to the application with a parameter of 2 and then run up the application. Clicking on the different buttons will increment the count value according to their different parameters. The Value property of the Caliburn Micro Parameter is a dependency property, which means it also supports the usual WPF data binding. This allows you to use it in all sorts of different scenarios you come across.

Pro Tip: Because of the flexibity of using data binding to set the parameter value, it is possible to pass UI elements from the view into the view-model. You should try to avoid doing this as hard as you possibly can! UI elements in the view-model can fracture your MVVM archetecture and can cause maintenance issues in the future.

Short Syntax

Now to learn how to use the short syntax to do the same thing. To look into this, let’s start off with a fresh copy of the application that doesn’t have our recent long syntax experiments in it. Again we will start by modifying the application without changing its current behaviour. This time we only need to add the Caliburn Micro namespace, and replace the repeat button with this new one:

<RepeatButton Content="Up" Margin="15" VerticalAlignment="Top"
              cal:Message.Attach="[Event Click] = [Action IncrementCount]" />

All we have done this time is use one of Caliburn Micro’s attached properties (Message.Attach) to specify which event we are interested in, and which method to call.

Next we look at event parameters using this short syntax. Modify the IncrementCount method in same way we did for the long syntax. Including an event parameter using Message.Attach will look like this:

cal:Message.Attach="[Event Click] = [Action IncrementCount(1)]"

The event parameter is written in the brackets after the method name. I’m sure you can work out how to add a button that increments the value by 2.

The short syntax even supports a special form of data binding. To demonstrate this, let’s add a button that increments the count by the count value itself. In other words, a button that doubles the count value. You can remove the CanIncrementCount event guard mentioned in the previous blog post to make the value go higher than 100. The repeat button code would look something like this:

<RepeatButton Content="Double" Margin="15"
              cal:Message.Attach="[Event Click] = [Action IncrementCount(Count.Text)]" />

Here I have set the parameter to be Count.Text. This sets up a binding to the Text property of the TextBlock (named Count) which is displaying the current value. Notice that Caliburn Micro automatically converts string values that we want to pass into a method that takes a numerical value. Another shortcut that Caliburn Micro provides here is that it will automatically use an appropriate property on a user control if we do not specify a property. In the example above, we could just write the name of the TextBlock (“Count”) as the parameter and Caliburn Micro will bind to the Text property by default. Here is the what the application looks like so far:

Event Parameters

Automatically Finding Parameters

To finish off this tutorial I’ll mention that Caliburn Micro even has conventions for automatically picking up parameters when you don’t explicitly set them. If you do not explicitly specify a parameter, Caliburn Micro will look at the parameter name in the method signiture and try find any user control in the view that matches this name (ignoring the case). If a matching user control is found, an appropriate property on the control will be used to provide the parameter. For example, if the user control is a TextBlock, the Text property value will be used as the parameter. Again, Caliburn Micro can automatically convert strings to ints and so on if necessary.

To understand this convention more easily, lets try this out in the application. Add a slider to the application and call it “Delta”. Then add another button called “IncrementCount”. As explained in the previous blog post, the button is going to automatically call the IncrementCount method when it is clicked. This time however, the method has a parameter, but we havn’t specified what value the button should use. Notice that the slider we added is the same name as the parameter (delta). Thus Caliburn Micro will automatically use the Value property of the slider as the parameter to the method whenever the button is clicked. Here is all the code we needed to add to do this:

<UniformGrid Columns="2" VerticalAlignment="Bottom">
  <Slider Name="Delta" Minimum="0" Maximum="5" Margin="15" />
  <Button Name="IncrementCount" Content="Increment" Margin="15" />
</UniformGrid>

Parameter Convention

Extra for Experts

Here I’ve only covered some of the support that Caliburn Micro provides for hooking up events. Some other topics of intrest include:

  • Setting action targets
  • Special parameter values for data binding
  • Action bubbling
  • Action guards with parameters

You can find more information about hooking up events using Caliburn Micro from the online documentation. I recommend reading through the documentation so you can better choose which approaches to use for the various event scenarios in your application. You’ll find there is a lot of helpful support that Caliburn Micro provides, and a lot of convenient conventions that will take work off your shoulders. The Cheat Sheet is a useful page to bookmark. You’ll also find that the HelloExplicitAction, HelloParameters and BubblingAction samples are a good source of knowledge.

You can download the application from this tutorial used to demonstrate the long syntax from here, and the short syntax from here.

Next let’s take a look at the Event Aggregator.

Until next time, Happy Coding!

Tagged as WPF

8 Responses to “Caliburn Micro Part 3: More About Events and Parameters”

  • * Also worth mentioning is the parameter hookup in the viewmodel when you use conventions

    http://pastebin.com/ZS9djZW0

    Note that case is not sensitive (Count/count)
    Note that CM does the type conversation from string to int for you. Thanks CM

    * Referring to Action bubbling is a good thing because it’s one of the most powerful features IMO which can really alter the way one composes the app.

    * I would like to see some practical use cases for the setting action targets since I haven’t had a need for them (or maybe I employ workarounds without knowing)

    * “Event guards with parameters”. I don’t think you are referring to action guards right? What are event guards?

    * Some minor feedback. I would have emphasized the short syntax and show the equivalent at the end or in a sperate post. No need to scare away lazy developers from CM when they get introduced to it :)
    But that’s probably because I’m a text loving dev who doesn’t use Blend and has to actually check it out

    Looking forward to your next part in the series. Event Aggregator seems like a good next subject

  • Thanks for the feedback Tom!

    I really like the parameter hookup feature using conventions, but wasn’t sure to include it originally. I have now updated the post with an extra section demonstrating this feature.

    Also, I was in fact refering to action gaurds when I mentioned event guards. Thanks for pointing out the proper jargon.

    -Jason

  • [...] Part 1: Getting Started Part 2: Data Binding and Events Part 3: More About Events and Parameters [...]

  • [...] 1: Getting Started Part 2: Data Binding and Events Part 3: More About Events and Parameters Part 4: The Event [...]

  • What if you had two numbers on this window. Would you be able to use the same IncrementCount method (and thus the same buttons) on an Object (say, which ever number had focus)? So, instead of passing an integer, pass a reference to a variable that should be incremented?

  • Hello Randy

    It would not be easy to use the focused number, but instead you could give the numbers a selected state. Fore example, put them into a list box. Then you could either pass the selected item as a command parameter to the IncrementCount method, or have a selected item property in the view model which is binding to the list box – then the method could look at this property to know which number to increase. I’d go for the selected-item property idea.

    -Jason

  • hi,
    i have a doubt ” How to add Multiple Events to a Control”

    Eg : click event and mouse over event on same button….how it will be possible

  • Hello Abdul

    For the short syntax, you can attach multiple events by separating them with a semicolon like this:

    cal:Message.Attach="[Event Click] = [Action IncrementCount(Count.Text)]; [Event MouseEnter] = [Action PrintMessage]"

    Or for the long syntax, you can add multiple event triggers such as this:

    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
        <cal:ActionMessage MethodName="IncrementCount">
          <cal:Parameter Value="{Binding Count}" />
        </cal:ActionMessage>
      </i:EventTrigger>
      <i:EventTrigger EventName="MouseEnter">
        <cal:ActionMessage MethodName="PrintMessage" />
      </i:EventTrigger>
    </i:Interaction.Triggers>
  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top