MVVM Light Toolkit V3 Alpha 2: EventToCommand behavior

.NET, Blend, MVVM, Silverlight, Technical stuff, Work, WPF
No Comments

This post was imported from my old blog and had 42 comments which are included as a screenshot at the end of this post.

Update (11/14/2009): I updated EventToCommand with a new feature: You can now pass the EventArgs of the fired event to the invoked command. See this post for more explanations.

Here is another early release of the MVVM Light Toolkit V3 (Alpha 2). I decided to release gradually and early as soon as a new part of this new version is ready, to allow advanced users to install, test and give feedback about the new features. If you haven’t seen it yet, the features available in V3 Alpha 1 are described in a previous article. There will be a few more alphas before I make a V3 release, which means more good things are a-coming ;)

Usual disclaimer: Alpha releases are not feature complete (meaning that APIs may change) and it is very possible that there are bugs in the code. Use with care and give feedback if something is not working, thanks!!

EventToCommand behavior

The new feature available in V3 Alpha2 is called EventToCommand and is a Blend behavior. These pieces of code are optimized for Expression Blend, but can also be added directly in XAML, as we will see in this article.

EventToCommand is used to bind an event to an ICommand directly in XAML.

Note: Even though Expression Blend facilitates the usage of EventToCommand, it is not a prerequisite. EventToCommand can be used even if Expression Blend is not installed on your system, or on your users’ system.

Credits, History

This behavior reuses much code from the Expression Blend sample behavior named InvokeDataCommand. I want to give props to the Expression team for creating and publishing these great samples. This would not have been possible without the work put into these samples. I want to especially thank Pete Blois and Jeff Kelly of the Expression team for their help.

I also want to thank Rishi, the creator of the nRoute toolkit, for the interesting discussions and a couple of ideas that I implemented in EventToCommand.

If you are already using InvokeDataCommand, the new EventToCommand behavior brings the following additional features:

  • WPF / Silverlight compatibility: The WPF version of the Expression Blend sample behavior InvokeDataCommand has a bug that prevents it to work (the Silverlight version runs fine though). The bug is corrected in EventToCommand, and both versions run well.
  • CommandParameter is bindable. You can bind this property, for example, to the value of a slider, the content of a TextBox, or any other property that is accessible to a data binding.
  • Disabling the attached control: If the IsEnabled property is available for the attached element, you can opt-in to automatically disable the element if the Command’s CanExecute method returns false. This is dynamic, i.e. if the value of CanExecute changes, the element will be disabled/enabled.
    • In Silverlight, this is valid for all Controls.
    • In WPF, this is valid for all FrameworkElements (Panels, Shapes, Controls, etc…).
    • Note: By default, the element will not be disabled/enabled automatically. Since one element can have multiple EventToCommand behaviors added to link multiple events to commands, you probably want only one or two of these to affect the IsEnabled property. This can be turned on by using the MustToggleIsEnabled property, which can be either set in XAML (see below) or databound to a boolean value (checkbox, etc…).

Source code, Binaries

The source code is available on the Codeplex page.

The binaries can be found here.

Features, Usage

EventToCommand is a behavior that can be added to any FrameworkElement. This can be a Rectangle, an Ellipse (in fact, any shape), an Image, any Control (Button, Slider, CheckBox, RadioButton, and many many others) etc. In short: If you can add an element to your UI, you can probably add EventToCommand to it.

For more information about ICommand (and their MVVM Light implementation, RelayCommand), read this article. You can bind any event to any command. Typically, you will use this to link an element’s event to a command defined in a ViewModel class. For more information about the ViewModel pattern in WPF and Silverlight, this page will help you.

In Expression Blend:

Adding an EventToCommand to any element in Expression Blend is super easy thanks to the visual support.

  • Right click on the References folder and select “Add Reference”.

  • Add a reference to the MVVM Light DLLs. You need two: GalaSoft.MvvmLight.dll and GalaSoft.MvvmLight.Extras.dll. In addition, you need the System.Windows.Interactivity.dll which contains the base code for all behaviors.
    You can download the DLLs needed here. 
  • Open your project in Expression Blend, and build it to make sure that everything is working fine.
  • Locate the element on which you want to add a command in the Objects and Timeline panel.
  • Open the Assets panel and find the Behaviors category.
    You can also find behaviors in the Asset library, which is the last button on the bottom of the toolbar.

FliCA4

  • Drag the EventToCommand behavior on the element you selected before in the Objects and Timeline panel.

  • With the EventToCommand selected, select the Properties panel.
  • Select the event you want to handle.

  • In the Miscellaneous section, bind the EventToCommand to the ICommand you want to execute when the event is fired.
    If you use the MVVM pattern, you probably want to use an ICommand (for example a RelayCommand) located in the ViewModel that is set as the DataContext for your window/page.
    In WPF, you can also enter a value, for example ApplicationCommands.Save. In that case, you must set a CommandBinding.

Fli249C

  • If you want to pass a parameter to the ICommand, you can set the CommandParameter property. You can data bind CommandParameter to something (for example the Text property of a TextBox, etc…). If you want to set a hard coded value ) for example “Hello world”, you need to set CommandParameterValue in the XAML editor (see the “Caveat” section below).

FliD557

  • Finally, if you want the attached element to be disabled depending on the ICommand.CanExecute method, set the MustToggleIsEnabledValue property to True. You can also use MustToggleIsEnabled to data bind this property to something else (for example a CheckBox’s IsChecked property) (see the “Caveat” section below).
    • In Silverlight, this will only work on Controls. Use the VisualStateManager to modify the appearance of the disabled control.
    • In WPF, any FrameworkElement can be disabled. Use the Triggers panel to modify the appearance of the FrameworkElement when it is disabled.


In XAML

Using the XAML editor, follow the steps to add an EventToCommand to an element.

  • Add a reference to the MVVM Light DLLs. You need two: GalaSoft.MvvmLight.dll and GalaSoft.MvvmLight.Extras.dll. In addition, you need the System.Windows.Interactivity.dll which contains the base code for all behaviors.
    You can download the DLLs needed here. 
  • Add an xmlns for the following namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
  • Add the EventToCommand to the desired element (in this example, a Rectangle) with the following XAML code:
    This presupposes that the DataContext of your page/window is set to a ViewModel containing the TestCommand command, as is usual in the MVVM pattern.

<Rectangle Fill="White"
           Stroke="Black"
           Width="200"
           Height="100">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <cmd:EventToCommand Command="{Binding TestCommand,
                                          Mode=OneWay}"
               CommandParameter="{Binding Text,
                                  ElementName=MyTextBox,
                                  Mode=OneWay}"
               MustToggleIsEnabledValue="True" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Rectangle>

Listening to events on other elements

Because EventToCommand derives from System.Windows.Interactivity.TriggerAction<T>, it has a property named SourceName. With this property, you can attach EventToCommand to an element, but listen to events on another element. I didn’t explicitly forbid this in the code, but I would recommend against it. I think that it creates confusing code that can easily be broken. The best is probably to always listen to events on the attached element itself, and leave SourceName empty.

Small caveat

Because of limitations in the Silverlight framework (specifically, the fact that data bindings can only be applied to a FrameworkElement), I had to resort to a small trick to make CommandParameter and MustToggleIsEnabled bindable. You will see in the code that there are four properties:

  • CommandParameter:
    • In Silverlight, used to data bind CommandParameter.
    • In WPF, used either for data binding or for hard coded values.
  • CommandParameterValue:
    • In Silverlight and in WPF, used for hard coded values only.
  • MustToggleIsEnabled:
    • In Silverlight, used to data bind MustToggleIsEnabled.
    • In WPF, used either for data binding or for hard coded values.
  • MustToggleIsEnabledValue:
    • In Silverlight and in WPF, used for hard coded values only.

In short, if you don’t care about Silverlight compatibility for your XAML code, you can always use CommandParameter or MustToggleIsEnabled in WPF, either for data binding or for hard coded values. If you want to share your XAML between a Silverlight and a WPF application, then you should respect the rules above, or else you will get exceptions in Silverlight when the XAML is being parsed.

Demo application

The demo application shows multiple usages of the EventToCommand behavior. The application runs in Silverlight and in WPF. Feel free to download the code and play with it to learn how to use EventToCommand! The Silverlight version of the sample application can also be executed directly in your web browser.

  • Binding a Button’s Click event and a Rectangle’s MouseEnter event to a simple RelayCommand.
  • Binding a Button’s Click event and a Rectangle’s MouseEnter event to a RelayCommand with a data bound parameter.
  • Binding a Button’s Click event and a Rectangle’s MouseEnter event to a RelayCommand with a hard coded parameter.
  • Binding a Button’s Click event and a Rectangle’s MouseEnter event to a RelayCommand and disabling them depending on the parameter’s value.
    Note: In Silverlight, Rectangles cannot be disabled.
  • Passing the EventArgs of a fired event to the invoked command.
    Note: This feature was added after V3 alpha 2 was released. See this post for more information.

License

MVVM Light Toolkit is distributed under the MIT License. This license grants you the right to do pretty much anything you want with the code, but don’t come crying if you break something (the exact wording is found here). Some parts of the GalaSoft.MvvmLight.Extras DLL are licensed under the MS-PL license.

GalaSoft Laurent Bugnion
Laurent Bugnion (GalaSoft)

Share on Facebook

This post was imported from my old blog. Original comments screenshot: 12-14-2013 5-04-22 PM

Leave a Reply