Passing event args and sender to the RelayCommand
Asked Answered
T

3

16

How do you get event sender when using RelayCommand?

Thoraco answered 3/6, 2010 at 6:51 Comment(0)
T
25

This is one of those pain-in-the-%¤# answers where I don't actually answer your question, but instead lecture you about what you should be doing differently. So, sorry about that. Here goes:

If you find yourself in a position where you need to get at the sender object in your viewmodel, then you should probably do something different. By referencing, say, a Button or a ListBox in your viewmodel you have made that viewmodel aware of UI concepts that it should not know anything about. My suggestion is to instead hook up to the event in the code-behind page, find out what you need to know about the sender or what-not, and then execute the viewmodel command programmatically. That is also breaking the MVVM "rules", but IMHO it is a much slighter hack than referencing the sender in your viewmodel.

Tercel answered 3/6, 2010 at 9:20 Comment(3)
Just as the VM shouldn't expose Visibilty (and instead use a converter in the XAML), maybe there should be some way to use a converter for going the other way ... convert from a View based eventarg into a non-view type?Millisent
How is your suggestion also breaking MVVM rules? Seems fine to me.Disgruntle
I think my main problem at the time was that it is overly complicated compared to just binding the button (in the view) to the command in the VM. Looking at it now, I think you are right. It doesn't really break any rules.Ardennes
S
11

I was having a similar problem, but only needed to get the EventArgs. Gladly, this was absurdly simple once I found the answer in another thread here at Stack Overflow.

<cmd:EventToCommand Command="{Binding SomeCommand, Mode=OneWay}" PassEventArgsToCommand="True"/>

Once you know about that magic "PassEventArgsToCommand" setting, you're golden. Just use a RelayCommand<type> instead of a plain RelayCommand.

I hope this helps.

Solatium answered 3/6, 2010 at 21:31 Comment(2)
Just want to comment on that: PassEventArgsToCommand is not very clean, because it breaks the separation of concerns by bring a UI class (the EventArgs) into the VM. Using this renders your VM less testable. However there are scenarios (drag&drop, for instance) where anything else would be even dirtier. This is why I added this into EventToCommand. Use with a lot of care though!Malapropism
Although the PassEventArgsToCommand may not be clean, I found it useful trying to add SkyDrive support to my WP7 app. The signin button passes the live session information via the event args. I could probably handle the event in code-behind, set the Session property onto the ViewModel and then invoke a command. The PassEventArgsToCommand helps write comprehensible code.Amianthus
C
7

This can be done by binding the sender to the Command Parameter.

<command:EventToCommand
              Command="{Binding CommandName}"
              CommandParameter="{Binding RelativeSource=
                                         { RelativeSource FindAncestor, 
                                           AncestorType={x:Type TypeOfSender},
                                           AncestorLevel=1}}" 
              PassEventArgsToCommand="True" >
</command:EventToCommand>
Como answered 11/12, 2012 at 21:53 Comment(2)
I upvoted this because while Henrik is correct in explaining that this shouldn't be done, the world isn't perfect and achieving pure MVVM is sometimes impossible. For instance, if you want a Textbox to select all text when it receives focus, you'll need the TextBox itself to call its SelectAll() member. It's undoubtedly doable in MVVM but it'll create insanely complex code, whereas this solution is, in some situations, "good enough". I agree that this behaviour should be discouraged as much as possible, but sometimes you just need to be pragmatic and a fix like this, while ugly, works.Muraida
Another example: the WPF WebBrowser control. you can bind a command to the Navigated event, but if you actually want to do something with the http response, you need a reference to the browser itself, because that information isn't in the eventargs.Muraida

© 2022 - 2024 — McMap. All rights reserved.