title | page_title | description | slug | tags | published | position |
---|---|---|---|---|---|---|
EventToCommandBehavior |
EventToCommandBehavior |
EventToCommandBehavior |
common-event-to-command-behavior |
eventtocommandbehavior |
true |
15 |
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.
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:
{{region common-event-to-command-behavior_01}} <telerik:RadListBox ItemsSource="{Binding ListBoxItems}" /> {{endregion}}
Which DataContext is the ViewModel below:
{{region common-event-to-command-behavior_01}} public class ViewModel: ViewModelBase { public ObservableCollection ListBoxItems { get; set; }
public ViewModel()
{
this.ListBoxItems = new ObservableCollection<string> { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
}
}
{{endregion}}
And you need to handle the MouseEnter event of the ListBox, the EventToCommandBehavior will easily allow you to bind that event to a command in the ViewModel. You would just need to add object of type EventBinding to the EventToCommandBehavior.EventBindings collection. The EventBinding object contains few properties, in this case you will need to use the Command property which should be bound to the desired Command and the Event property which represents the event you want to handle:
{{region common-event-to-command-behavior_02}} <telerik:RadListBox x:Name="ListBox" ItemsSource="{Binding ListBoxItems}"> telerik:EventToCommandBehavior.EventBindings <telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseEnter" /> </telerik:EventToCommandBehavior.EventBindings> </telerik:RadListBox> {{endregion}}
The last thing you should do is to define the custom command in the ViewModel as shown below:
{{region common-event-to-command-behavior_02}} public ICommand CustomCommand { get; set; } ... public ViewModel() { ... this.CustomCommand = new DelegateCommand(OnCustomCommandExecuted); }
private void OnCustomCommandExecuted(object obj)
{
MessageBox.Show("Command Executed!");
}
{{endregion}}
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:
{{region common-event-to-command-behavior_03}} telerik:EventToCommandBehavior.EventBindings <telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" /> </telerik:EventToCommandBehavior.EventBindings> {{endregion}}
The result will be the same command executed when the ListBox is Clicked.
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.
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:
{{region common-event-to-command-behavior_04}} telerik:EventToCommandBehavior.EventBindings <telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" CommandParameter="This is a command parameter!"/> </telerik:EventToCommandBehavior.EventBindings> {{endregion}}
And the method in the ViewModel should look as follows:
{{region common-event-to-command-behavior_03}} private void OnCustomCommandExecuted(object obj) { MessageBox.Show(obj.ToString()); } {{endregion}}
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.
{{region common-event-to-command-behavior_05}} telerik:EventToCommandBehavior.EventBindings <telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" PassEventArgsToCommand="True" /> </telerik:EventToCommandBehavior.EventBindings> {{endregion}}
{{region common-event-to-command-behavior_04}} private void OnCustomCommandExecuted(object obj) { var clickedItem = (obj as MouseButtonEventArgs).OriginalSource as TextBlock; if (clickedItem != null) { MessageBox.Show("Clicked Item: " + clickedItem.Text); } } {{endregion}}
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.
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:
{{region common-event-to-command-behavior_06}} telerik:EventToCommandBehavior.EventBindings <telerik:EventBinding Command="{Binding CustomCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" /> <telerik:EventBinding Command="{Binding AnotherCommand}" EventName="MouseLeftButtonDown" RaiseOnHandledEvents="True" /> </telerik:EventToCommandBehavior.EventBindings> {{endregion}}
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).