What\'s a good method to bind Commands to Events? In my WPF app, there are events that I\'d like to capture and process by my ViewModel but I\'m not sure how. Things like lo
Have a look at Marlon Grech's Attached Command Behaviour, it could be exactly what you're looking for
I don't think you can use it in pure XAML, but take a look at the Delegate Command.
Use System.Windows.Interactivity
…xmlns:i=http://schemas.microsoft.com/expression/2010/interactivity…
<Slider
<i:Interaction.Triggers>
<i:EventTrigger EventName="ValueChanged">
<i:InvokeCommandAction
Command="{Binding MyCommand}"
CommandParameter="{Binding Text, ElementName=textBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Slider>
Make sure your project references the assembly System.Windows.Interactivity.
Source: MSDN Blog Executing a command from an event of your choice
[Update] Have a look to to Microsoft.Xaml.Behaviors.Wpf (available since 03.12.2018) Official package by Microsoft.
Execute Command, Navigate Frame, and Delegating Command behaviour is a pretty good pattern. It is also can be used in the Expression Blend.
On the "best practices" side, you should think twice before converting an event to a command. Normally, command is something user does intentionaly, an event most often is just an interaction trail, and should not leave the view boundaries.
In order to handle events, you must have some code that attaches itself to the event and executes your command in response. The final goal is to have in XAML:
MouseMoveCommand="{Binding MyCommand}"
In order to achieve this you need to define an attached property for each event that you want to handle. See this for an example and a framework for doing this.
I implemented it using Attached Properties and Reflection. I cannot say it is the best implementation, but I will maybe improve it and it may be a good start for you.
public class EventBinding : DependencyObject
{
public static string GetEventName(DependencyObject obj)
{
return (string)obj.GetValue(EventNameProperty);
}
public static void SetEventName(DependencyObject obj, string value)
{
obj.SetValue(EventNameProperty, value);
var eventInfo = obj.GetType().GetEvent(value);
var eventHandlerType = eventInfo.EventHandlerType;
var eventHandlerMethod = typeof(EventBinding).
GetMethod("EventHandlerMethod", BindingFlags.Static | BindingFlags.NonPublic);
var eventHandlerParameters = eventHandlerType.GetMethod("Invoke").GetParameters();
var eventArgsParameterType = eventHandlerParameters.
Where(p => typeof(EventArgs).IsAssignableFrom(p.ParameterType)).
Single().ParameterType;
eventHandlerMethod = eventHandlerMethod.MakeGenericMethod(eventArgsParameterType);
eventInfo.AddEventHandler(obj, Delegate.CreateDelegate(eventHandlerType, eventHandlerMethod));
}
private static void EventHandlerMethod<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs
{
var command = GetCommand(sender as DependencyObject);
command.Execute(new EventInfo<TEventArgs>(sender, e));
}
public static readonly DependencyProperty EventNameProperty =
DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventHandler));
public static ICommand GetCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventBinding));
}
public class EventInfo<TEventArgs>
{
public object Sender { get; set; }
public TEventArgs EventArgs { get; set; }
public EventInfo(object sender, TEventArgs e)
{
Sender = sender;
EventArgs = e;
}
}
public class EventInfo : EventInfo<EventArgs>
{
public EventInfo(object sender, EventArgs e)
: base(sender, e) { }
}
public class EventBindingCommand<TEventArgs> : RelayCommand<EventInfo<TEventArgs>>
where TEventArgs : EventArgs
{
public EventBindingCommand(EventHandler<TEventArgs> handler)
: base(info => handler(info.Sender, info.EventArgs)) { }
}
<DataGrid local:EventBinding.EventName="CellEditEnding"
local:EventBinding.Command="{Binding CellEditEndingCommand}" />
private EventBindingCommand<DataGridCellEditEndingEventArgs> _cellEditEndingCommand;
public EventBindingCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand
{
get
{
return _cellEditEndingCommand ?? (
_cellEditEndingCommand = new EventBindingCommand<DataGridCellEditEndingEventArgs>(CellEditEndingHandler));
}
}
public void CellEditEndingHandler(object sender, DataGridCellEditEndingEventArgs e)
{
MessageBox.Show("Test");
}