将事件参数和发送者传递给RelayCommand

16

当使用RelayCommand时,如何获取事件发送者?

3个回答

25

这是一种令人烦恼的答案,我并没有直接回答你的问题,而是讲述了你应该采取不同的方式。如果你发现自己需要在viewmodel中获取发送对象,那么你应该考虑做一些不同的事情。通过引用视图模型中的按钮或列表框等UI元素,会使得视图模型了解它不应该知道的UI概念。我的建议是在代码后端页面中连接到事件,找出关于发送者或其他信息需要了解的内容,然后以编程方式执行viewmodel命令。这也违反了MVVM“规则”,但在我看来,这比在视图模型中引用发送者要好得多。


就像 VM 不应该暴露 Visibilty 一样(而是在 XAML 中使用转换器),也许应该有某种方法来使用转换器来进行另一种方式的转换...将基于 View 的 eventarg 转换为非 View 类型? - Kirk Kuykendall
你的建议也违反了MVVM规则吗?在我看来很好啊。 - Tim Pohlmann
我认为当时我的主要问题是与只需将(视图中的)按钮绑定到VM中的命令相比,它过于复杂。现在看来,我认为你是对的。它并没有真正违反任何规则。 - Henrik Söderlund

11

我遇到了类似的问题,但只需要获取EventArgs。幸运的是,一旦我在Stack Overflow的另一个线程中找到答案,这就非常简单了。

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

一旦你了解了那个神奇的 "PassEventArgsToCommand" 设置,你就万事大吉了。只需使用 RelayCommand<type> 而不是普通的 RelayCommand。

我希望这能帮到你。


6
仅想就此发表一下意见:PassEventArgsToCommand不太干净,因为它通过将一个UI类(EventArgs)带入VM来打破了关注点分离。使用此方法会使您的VM难以进行测试。但是在某些情况下(例如拖放),其他任何方法都会更加不干净。这就是我将其添加到EventToCommand中的原因。但是请务必小心使用! - LBugnion
2
虽然PassEventArgsToCommand可能不太干净,但我发现在尝试为我的WP7应用添加SkyDrive支持时它很有用。登录按钮通过事件参数传递了实时会话信息。我可以在代码后台中处理事件,将Session属性设置到ViewModel上,然后调用命令。PassEventArgsToCommand有助于编写易于理解的代码。 - rams

7
这可以通过将发送者绑定到命令参数来完成。
<command:EventToCommand
              Command="{Binding CommandName}"
              CommandParameter="{Binding RelativeSource=
                                         { RelativeSource FindAncestor, 
                                           AncestorType={x:Type TypeOfSender},
                                           AncestorLevel=1}}" 
              PassEventArgsToCommand="True" >
</command:EventToCommand>

2
我点赞了这个帖子,因为虽然Henrik在解释这不应该被做的时候是正确的,但世界并不完美,有时候实现纯粹的MVVM是不可能的。例如,如果你想让一个文本框在获得焦点时选择所有文本,你需要让文本框自己调用它的SelectAll()成员。这无疑可以在MVVM中完成,但会创建非常复杂的代码,而这个解决方案在某些情况下是“足够好”的。我同意应该尽可能地避免这种行为,但有时候你只需要务实一点,像这样的修复虽然丑陋,但是有效的。 - Bas
3
另一个例子:WPF WebBrowser控件。您可以将命令绑定到Navigated事件,但是如果您想要对http响应执行某些操作,则需要引用浏览器本身,因为该信息不在事件参数中。 - Bas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接