How to get the EventArgs as a CommandParameter using the AttachedCommandBehaviour
I have been asked many times how can I get the event args as a command parameter when using the AttachedCommandBehaviour.
Well the library does not support such a feature. I can do that yet I feel like the EventArgs should not flow down to the ViewModel because as such that is a UI thing… Yet in some case (such as for example if you want to set the Handled property to true of the Event args) this is needed.
I decided not to add this in the library yet I am gonna show how one can get this to work with some Attached Behavior.
The idea is to have a Attached Dependency property that handles the event and stores the last Event Args in another Attached Dependency Property. Here is the code to do so
1: public class MouseEventArgsHandler
2: {
3: #region LastMouseEventArgs
4:
5: /// <summary>
6: /// LastMouseEventArgs Attached Dependency Property
7: /// </summary>
8: public static readonly DependencyProperty LastMouseEventArgsProperty =
9: DependencyProperty.RegisterAttached("LastMouseEventArgs", typeof(MouseButtonEventArgs), typeof(MouseEventArgsHandler),
10: new FrameworkPropertyMetadata((MouseButtonEventArgs)null));
11:
12: /// <summary>
13: /// Gets the LastMouseEventArgs property. This dependency property
14: /// indicates ....
15: /// </summary>
16: public static MouseButtonEventArgs GetLastMouseEventArgs(DependencyObject d)
17: {
18: return (MouseButtonEventArgs)d.GetValue(LastMouseEventArgsProperty);
19: }
20:
21: /// <summary>
22: /// Sets the LastMouseEventArgs property. This dependency property
23: /// indicates ....
24: /// </summary>
25: public static void SetLastMouseEventArgs(DependencyObject d, MouseButtonEventArgs value)
26: {
27: d.SetValue(LastMouseEventArgsProperty, value);
28: }
29:
30: #endregion
31:
32: #region HandleMouseDoubleClick
33:
34: /// <summary>
35: /// HandleMouseDoubleClick Attached Dependency Property
36: /// </summary>
37: public static readonly DependencyProperty HandleMouseDoubleClickProperty =
38: DependencyProperty.RegisterAttached("HandleMouseDoubleClick", typeof(bool), typeof(MouseEventArgsHandler),
39: new FrameworkPropertyMetadata((bool)false,
40: new PropertyChangedCallback(OnHandleMouseDoubleClickChanged)));
41:
42: /// <summary>
43: /// Gets the HandleMouseDoubleClick property. This dependency property
44: /// indicates ....
45: /// </summary>
46: public static bool GetHandleMouseDoubleClick(DependencyObject d)
47: {
48: return (bool)d.GetValue(HandleMouseDoubleClickProperty);
49: }
50:
51: /// <summary>
52: /// Sets the HandleMouseDoubleClick property. This dependency property
53: /// indicates ....
54: /// </summary>
55: public static void SetHandleMouseDoubleClick(DependencyObject d, bool value)
56: {
57: d.SetValue(HandleMouseDoubleClickProperty, value);
58: }
59:
60: /// <summary>
61: /// Handles changes to the HandleMouseDoubleClick property.
62: /// </summary>
63: private static void OnHandleMouseDoubleClickChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
64: {
65: Control control = d as Control;
66: if (control != null)
67: {
68: if ((bool)e.NewValue)
69: control.MouseDoubleClick += ControlMouseDoubleClick;
70: else
71: control.MouseDoubleClick -= ControlMouseDoubleClick;
72: }
73: }
74:
75: static void ControlMouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
76: {
77: SetLastMouseEventArgs((DependencyObject)sender, e);
78: }
79:
80: #endregion
81: }
then you can use that value as the CommandParameter… Something like this
1: <ListBox ItemsSource="{Binding Data}"
2: local:MouseEventArgsHandler.HandleMouseDoubleClick="True"
3: acb:CommandBehavior.Event="MouseDoubleClick"
4: acb:CommandBehavior.Command="{Binding DoIt}"
5: acb:CommandBehavior.CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(local:MouseEventArgsHandler.LastMouseEventArgs)}" />
and here is what the command in the ViewModel looks like
1: DoIt = new SimpleCommand
2: {
3: ExecuteDelegate = x =>
4: {
5: //set the event as handled
6: ((MouseButtonEventArgs)x).Handled = true;
7: System.Diagnostics.Debug.WriteLine("Event handled");
8: }
9: };
The down side of this is that you have to do an attached property for every different event you want to handle, yet at the same time this should be a rare case and if it is not then you should really re think what you are doing with MVVM.
Hope it helps
I created a demo project for anyone that wants to have a look.





Great stuff!
As soon as I saw your code on OnHandleMouseDoubleClickChanged I thought “Of course! Silly me!”. But that’s always the way, isn’t it?
hehe…. yea it happens to all of us
Ouch! I’ve found a nasty problem.
This only works if the dependency properties are created internally in a specific order. local:MouseEventArgsHandler.HandleMouseDoubleClick=”True” must be executed before any CommandBehaviour dependency property, otherwise the command won’t have access to MouseEventArgsHandler.LastMouseEventArgs, since subscriptions to events are executed in the same order you subscribed to them.
.
The problem, of course, is that this is XAML and you can’t control in which order they execute. I thought that the xaml parser would do it in the same order you declare them, but this doesn’t seem to be the case
I’ve fixed it using a Trigger. When MouseEventArgsHandler.HandleMouseDoubleClick is True, then I set the CommandBehaviour properties in setters, this way I’m sure about the order they get defined.
mmm… that is very true….
A safer way to do it is to forget the LastMouseEventArgs and instead in the HandleMouseDoubleClick get the command and call it directly.
I created a sample for you. here it is.
http://cid-96f8d49aa44c79c1.skydrive.live.com/self.aspx/Public/CommandForEventSamplev2.rar
Thanks marlon.
I see you’ve been working on… something that was needed
.
Great stuff indeed !
The same is really neat BUT for some reason where I use it in own MV-VM CommandBehavior.GetCommand() returns null in ControlMouseDoubleClick(object sender …) as if the sender had lost trace of the command somewhere.
Any idea of what happens ?
Also : I use it in a ListView, not a ListBox, if that can help (only difference I see).
send me an email with a sample project that I can try out.. my mail is marlongrech AT gmail DOT com… translate that to an email (done that because of spam readers)
ThX. I found the pb. I was setting a different DataContext for my listview and the command was never properly registred.