EventToCommandBehavior
When working in more advanced development scenarios we often find ourselves leaning towards the MVVM pattern for producing cleaner, loosely coupled, easier to test code, but along with this comes the responsibility of ensuring that all controls we are using can follow this pattern. While it is very easy to work with the event-based model that exists across the .Net framework, events do not play well into the mindset of reducing traditional code-behind and instead handling logic within a viewmodel. This is where the Telerik EventToCommandBehavior comes into use to allow your events to fire and your code to respond accordingly, all in the ViewModel without touching the code-behind of the UserControls.
Getting Started
Let's imagine that you need to use a RadListBox event in the ViewModel in order to execute some custom logic there. If you have the following RadListBox:
Example 1: Declare the RadListBox control
<telerik:RadListBox ItemsSource="{Binding ListBoxItems}" />
Example 2: Create the ViewModel class
public class ViewModel: ViewModelBase
{
public ObservableCollection<string> ListBoxItems { get; set; }
public ViewModel()
{
this.ListBoxItems = new ObservableCollection<string> { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
}
}
Example 3: Bind a specific event to a desired command
<telerik:RadListBox x:Name="ListBox" ItemsSource="{Binding ListBoxItems}">
<telerik:EventToCommandBehavior.EventBindings>
<telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseEnter" />
</telerik:EventToCommandBehavior.EventBindings>
</telerik:RadListBox>
Example 4: Define the custom command
public ICommand CustomCommand { get; set; }
...
public ViewModel()
{
...
this.CustomCommand = new DelegateCommand(OnCustomCommandExecuted);
}
private void OnCustomCommandExecuted(object obj)
{
MessageBox.Show("Command Executed!");
}
Figure 1: Execute a command through the EventToCommandBehavior
RaiseOnHandledEvents
Sometimes it appears that the event you need to handle is already handled in the code of the control. In the previous example the event wasn't handled in the code so there weren't any problems. However if you need to handle the MouseLeftButtonDown for an example you won't be able unless you set the RaiseOnHandledEvents property to True which allows you to raise handled events:
Example 5: Set the RasedOnHandledEvents property
<telerik:EventToCommandBehavior.EventBindings>
<telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" />
</telerik:EventToCommandBehavior.EventBindings>
Command Parameters
When binding to a command you will probably need to pass some data to the method that executes the command. The EventToCommandBehavior provides you with two options in this case - to pass whatever you need with the CommandParameter property or to pass the event arguments of handled event with the PassEventArgsToCommand property set to True.
Note that if you set both the properties at the same time, the CommandParameter is with higher priority than the PassEventArgsToCommand property.
CommandParameter
With the CommandParameter property you can easily pass an object or bind it to property of another control. Let's upgrade the example above by including a CommandParameter which will pass a simple string to the method in the ViewModel:
Example 6: Set the CommandParameter
<telerik:EventToCommandBehavior.EventBindings>
<telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True"
CommandParameter="This is a command parameter!"/>
</telerik:EventToCommandBehavior.EventBindings>
Example 7: Modify the method in the ViewModel class
private void OnCustomCommandExecuted(object obj)
{
MessageBox.Show(obj.ToString());
}
Figure 2: Modified method to use the command parameter
PassEventArgsToCommand
You can also pass the event arguments to the method by setting the PassEventArgsToCommand property to True. This will allow you to get the clicked element in same example and to use it as required.
Example 8: Set the PassEventArgsToCommand property
<telerik:EventToCommandBehavior.EventBindings>
<telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True"
PassEventArgsToCommand="True" />
</telerik:EventToCommandBehavior.EventBindings>
Example 9: Modify the method to use the EventArgs
private void OnCustomCommandExecuted(object obj)
{
var clickedItem = (obj as MouseButtonEventArgs).OriginalSource as TextBlock;
if (clickedItem != null)
{
MessageBox.Show("Clicked Item: " + clickedItem.Text);
}
}
Figure 3: Pass the EventArgs to the method
CommandTarget
The CommandTarget property of the EventBinding specifies the element where the command occurs. If CommandTarget is not set, the element that has keyboard focus will receive the command. For more details about the CommandTarget please check the CommandTarget Property topic.
Multiple Commands
The EventToCommandBehavior gives you the ability to add multiple EventBinidings. You can easily bind multiple commands to a single event as well as a single command to multiple events. For example we can execute two commands in the ViewModel when the MouseLeftButtonDown event of RadListBox is fired:
Example 10: Set multiple event bindings
<telerik:EventToCommandBehavior.EventBindings>
<telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" />
<telerik:EventBinding Command="{Binding AnotherCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" />
</telerik:EventToCommandBehavior.EventBindings>
If you have multiple commands attached to a single event, the commands will be executed in the order they are defined in the EventBindings collection (from top to bottom).
Failing Bindings
There are some cases where an event could be raised before the Command binding of the EventBinding is evaluated. Thus, the events would not be handled. There are a couple solutions for such scenarios. For the purpose of the examples, the AutoGeneratingColumn event of RadGridView will be used.
Use ElementName for the Command binding
Example 11: Set ElementName binding for the Command
<telerik:EventBinding Command="{Binding ElementName=gridView, Path=DataContext.AutoGeneratingColumnCommand}" EventName="AutoGeneratingColumn" PassEventArgsToCommand="True"/>
Set the DataContext of the Window in XAML
Example 12: Set the DataContext of the Window in XAML
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
Add the EventBinding programmatically
Example 13: Add the EventBinding programmatically
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
EventToCommandBehavior.GetEventBindings(gridView).Add(new Telerik.Windows.Controls.EventBinding()
{
EventName = "AutoGeneratingColumn",
Command = (gridView.DataContext as MainWindowViewModel).AutoGeneratingColumnCommand,
PassEventArgsToCommand = true
});
}