MVVM 将 EventArgs 作为命令参数传递
我正在使用 Microsoft Expression Blend 4
我有一个浏览器..,
[ XAML ] ConnectionView“后面有空代码”
<WebBrowser local:AttachedProperties.BrowserSource="{Binding Source}">
<i:Interaction.Triggers>
<i:EventTrigger>
<i:InvokeCommandAction Command="{Binding LoadedEvent}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Navigated">
<i:InvokeCommandAction Command="{Binding NavigatedEvent}" CommandParameter="??????"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</WebBrowser>
[ C# ] AttachedProperties 类
public static class AttachedProperties
{
public static readonly DependencyProperty BrowserSourceProperty = DependencyProperty . RegisterAttached ( "BrowserSource" , typeof ( string ) , typeof ( AttachedProperties ) , new UIPropertyMetadata ( null , BrowserSourcePropertyChanged ) );
public static string GetBrowserSource ( DependencyObject _DependencyObject )
{
return ( string ) _DependencyObject . GetValue ( BrowserSourceProperty );
}
public static void SetBrowserSource ( DependencyObject _DependencyObject , string Value )
{
_DependencyObject . SetValue ( BrowserSourceProperty , Value );
}
public static void BrowserSourcePropertyChanged ( DependencyObject _DependencyObject , DependencyPropertyChangedEventArgs _DependencyPropertyChangedEventArgs )
{
WebBrowser _WebBrowser = _DependencyObject as WebBrowser;
if ( _WebBrowser != null )
{
string URL = _DependencyPropertyChangedEventArgs . NewValue as string;
_WebBrowser . Source = URL != null ? new Uri ( URL ) : null;
}
}
}
[ C# ] ConnectionViewModel 类
public class ConnectionViewModel : ViewModelBase
{
public string Source
{
get { return Get<string> ( "Source" ); }
set { Set ( "Source" , value ); }
}
public void Execute_ExitCommand ( )
{
Application . Current . Shutdown ( );
}
public void Execute_LoadedEvent ( )
{
MessageBox . Show ( "___Execute_LoadedEvent___" );
Source = ...... ;
}
public void Execute_NavigatedEvent ( )
{
MessageBox . Show ( "___Execute_NavigatedEvent___" );
}
}
[ C# ] ViewModelBase 类 此处
最后:
与命令的绑定效果很好,并且显示消息框
我的问题:
当导航事件发生时,如何将NavigationEventArgs作为命令参数传递?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
它不容易得到支持。这是一篇文章,其中包含有关如何将 EventArgs 作为命令参数传递的说明。
您可能想考虑使用 MVVMLight - 它直接支持命令中的 EventArgs;你的情况看起来像这样:
It's not easily supported. Here's an article with instructions on how to pass EventArgs as command parameters.
You might want to look into using MVVMLight - it supports EventArgs in command directly; your situation would look something like this:
我尝试将依赖关系保持在最低限度,因此我自己实现了这一点,而不是使用 MVVMLight 的 EventToCommand。到目前为止对我有用,但欢迎反馈。
Xaml:
ViewModel:
EventToCommandBehavior:
ActionCommand:
I try to keep my dependencies to a minimum, so I implemented this myself instead of going with EventToCommand of MVVMLight. Works for me so far, but feedback is welcome.
Xaml:
ViewModel:
EventToCommandBehavior:
ActionCommand:
我总是回到这里寻找答案,所以我想做一个简短的简单的答案。
有多种方法可以执行此操作:
1. 使用 WPF 工具。最简单。
添加命名空间:
System.Windows.Interactivitiy
Microsoft.Expression.Interactions
XAML:
使用
EventName
调用您想要的事件,然后指定您的MethodName
中的 >Method 名称。代码:
2.使用MVVMLight。最难的。
安装 GalaSoft NuGet 包。
获取命名空间:
System.Windows.Interactivity
GalaSoft.MvvmLight .Platform
XAML:
使用
EventName
调用所需的事件,然后在绑定中指定您的Command
名称。如果要传递方法的参数,请将 PassEventArgsToCommand 标记为 true。代码实现委托:来源
为此,您必须获取 Prism MVVM NuGet 包。
不带
DelegateCommand
的代码:来源3. 使用 Telerik EventToCommandBehavior。这是一个选择。
您必须下载它的 NuGet 包。
XAML
:代码:
I've always come back here for the answer so I wanted to make a short simple one to go to.
There are multiple ways of doing this:
1. Using WPF Tools. Easiest.
Add Namespaces:
System.Windows.Interactivitiy
Microsoft.Expression.Interactions
XAML:
Use the
EventName
to call the event you want then specify yourMethod
name in theMethodName
.Code:
2. Using MVVMLight. Most difficult.
Install GalaSoft NuGet package.
Get the namespaces:
System.Windows.Interactivity
GalaSoft.MvvmLight.Platform
XAML:
Use the
EventName
to call the event you want then specify yourCommand
name in your binding. If you want to pass the arguments of the method, markPassEventArgsToCommand
to true.Code Implementing Delegates: Source
You must get the Prism MVVM NuGet package for this.
Code Without
DelegateCommand
: Source3. Using Telerik EventToCommandBehavior. It's an option.
You'll have to download it's NuGet Package.
XAML
:Code:
对于刚刚找到这篇文章的人,您应该知道,在较新的版本中(不确定确切的版本,因为官方文档在该主题上很少),如果未指定 CommandParameter,InvokeCommandAction 的默认行为是传递它作为 CommandParameter 附加到的事件。因此,原始海报的 XAML 可以简单地写为:
然后在您的命令中,您可以接受
NavigationEventArgs
类型的参数(或任何合适的事件参数类型),并且它将自动提供。For people just finding this post, you should know that in newer versions (not sure on the exact version since official docs are slim on this topic) the default behavior of the InvokeCommandAction, if no CommandParameter is specified, is to pass the args of the event it's attached to as the CommandParameter. So the originals poster's XAML could be simply written as:
Then in your command, you can accept a parameter of type
NavigationEventArgs
(or whatever event args type is appropriate) and it will automatically be provided.我知道这是一个相当老的问题,但我今天遇到了同样的问题,并且对引用所有 MVVMLight 不太感兴趣,这样我就可以使用带有事件参数的事件触发器。我过去使用过 MVVMLight,它是一个很棒的框架,但我只是不想再在我的项目中使用它。
我为解决这个问题所做的就是创建一个ULTRA最小、极其适应性强的自定义触发操作,它允许我绑定到命令并提供一个事件参数转换器来传递命令的 CanExecute 和 Execute 函数的参数。您不想逐字传递事件参数,因为这会导致视图层类型被发送到视图模型层(这在 MVVM 中永远不会发生)。
这是我提出的 EventCommandExecuter 类:
该类有两个依赖属性,一个允许绑定到视图模型的命令,另一个允许您在需要时绑定事件源。事件参数转换。如果需要,您还可以提供区域性设置(它们默认为当前 UI 区域性)。
此类允许您调整事件参数,以便它们可以被视图模型的命令逻辑使用。但是,如果您只想逐字传递事件参数,则只需不指定事件参数转换器即可。
在 XAML 中此触发器操作的最简单用法如下:
如果您需要访问事件源,则可以绑定到事件的所有者
(这假设您要附加触发器的 XAML 节点已被分配)
x:Name="SomeEventSource"
此 XAML 依赖于导入一些必需的命名空间
并创建一个
IValueConverter
(在本例中称为NameChangedArgsToStringConverter
)来对于基本转换器,我通常创建一个默认的静态只读转换器实例,然后我可以像上面所做的那样直接在 XAML 中引用该实例 。需要向任何项目添加一个类来使用交互框架,其方式与使用
InvokeCommandAction
的方式大致相同。添加一个类(大约 75 行)应该比添加一个类更可取。整个库来完成相同的结果。注意
这与 @adabyron 的答案有些相似,但它使用事件触发器而不是行为。该解决方案还提供了事件参数转换功能,而不是 @adabyron 的解决方案也无法做到这一点。我真的没有任何充分的理由为什么我更喜欢触发因素而不是行为,只是个人选择。 IMO 任一策略都是合理的选择。
I know this is a fairly old question, but I ran into the same problem today and wasn't too interested in referencing all of MVVMLight just so I can use event triggers with event args. I have used MVVMLight in the past and it's a great framework, but I just don't want to use it for my projects any more.
What I did to resolve this problem was create an ULTRA minimal, EXTREMELY adaptable custom trigger action that would allow me to bind to the command and provide an event args converter to pass on the args to the command's CanExecute and Execute functions. You don't want to pass the event args verbatim, as that would result in view layer types being sent to the view model layer (which should never happen in MVVM).
Here is the EventCommandExecuter class I came up with:
This class has two dependency properties, one to allow binding to your view model's command, the other allows you to bind the source of the event if you need it during event args conversion. You can also provide culture settings if you need to (they default to the current UI culture).
This class allows you to adapt the event args so that they may be consumed by your view model's command logic. However, if you want to just pass the event args on verbatim, simply don't specify an event args converter.
The simplest usage of this trigger action in XAML is as follows:
If you needed access to the source of the event, you would bind to the owner of the event
(this assumes that the XAML node you're attaching the triggers to has been assigned
x:Name="SomeEventSource"
This XAML relies on importing some required namespaces
and creating an
IValueConverter
(calledNameChangedArgsToStringConverter
in this case) to handle the actual conversion logic. For basic converters I usually create a defaultstatic readonly
converter instance, which I can then reference directly in XAML as I have done above.The benefit of this solution is that you really only need to add a single class to any project to use the interaction framework much the same way that you would use it with
InvokeCommandAction
. Adding a single class (of about 75 lines) should be much more preferable to an entire library to accomplish identical results.NOTE
this is somewhat similar to the answer from @adabyron but it uses event triggers instead of behaviours. This solution also provides an event args conversion ability, not that @adabyron's solution could not do this as well. I really don't have any good reason why I prefer triggers to behaviours, just a personal choice. IMO either strategy is a reasonable choice.
添加到 joshb 已经说过的内容 - 这对我来说效果很好。确保在您的 xaml 中添加对 Microsoft.Expression.Interactions.dll 和 System.Windows.Interactivity.dll 的引用:
我最终使用了类似的东西来满足我的需要。这表明您还可以传递自定义参数:
To add to what joshb has stated already - this works just fine for me. Make sure to add references to Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll and in your xaml do:
I ended up using something like this for my needs. This shows that you can also pass a custom parameter:
如果未设置
CommandParameter
,Prism 的InvokeCommandAction
将默认传递事件参数。https://learn.microsoft.com/en-us/previous-versions/msp-np/gg405494(v=pandp.40)#passing-eventargs-parameters-to-the-command
此处就是一个例子。请注意使用
prism:InvokeCommandAction
而不是i:InvokeCommandAction
。ViewModel
Prismlibrary 文档有新版本。
Prism's
InvokeCommandAction
will pass the event args by default ifCommandParameter
is not set.https://learn.microsoft.com/en-us/previous-versions/msp-n-p/gg405494(v=pandp.40)#passing-eventargs-parameters-to-the-command
Here is an example. Note the use of
prism:InvokeCommandAction
instead ofi:InvokeCommandAction
.The ViewModel
There is a new version of the Prismlibrary documentation.
我认为您不能使用
InvokeCommandAction
轻松做到这一点 - 我会看看EventToCommand
来自 MVVMLight 或类似版本。I don't think you can do that easily with the
InvokeCommandAction
- I would take a look atEventToCommand
from MVVMLight or similar.我知道现在有点晚了,但是 Microsoft 已将其 Xaml.Behaviors 开源,现在只需一个命名空间即可轻松使用交互性。
https://www.nuget.org/packages/Microsoft.Xaml.Behaviors .Wpf/
xaml。
然后像这样使用它,
PassEventArgsToCommand =“True”应设置为True,并且您实现的RelayCommand可以将RotedEventArgs或对象作为模板。如果您使用对象作为参数类型,只需将其转换为适当的事件类型。
该命令将如下所示,
该命令方法将如下所示,
“参数”将是路由事件对象。
如果您好奇的话,日志,
2020-12-15 11:40:36.3600|INFO|MyApplication.ViewModels.MainWindowViewModel|RoulatedEventArgs
如您所见,记录的 TypeName 是 RoutedEventArgs
RelayCommand impelmentation 可以在此处找到。
为什么使用 RelayCommand
PS:您可以绑定到任何控件的任何事件。就像Window的Closing事件一样,你会得到相应的事件。
I know it's a bit late but, Microsoft has made their Xaml.Behaviors open source and it's now much easier to use interactivity with just one namespace.
https://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Wpf/
xaml.
Then use it like this,
PassEventArgsToCommand="True" should be set as True and the RelayCommand that you implement can take RoutedEventArgs or objects as template. If you are using object as the parameter type just cast it to the appropriate event type.
The command will look something like this,
The command method will look something like this,
The 'parameter' will be the Routed event object.
And the log incase you are curious,
2020-12-15 11:40:36.3600|INFO|MyApplication.ViewModels.MainWindowViewModel|RoutedEventArgs
As you can see the TypeName logged is RoutedEventArgs
RelayCommand impelmentation can be found here.
Why RelayCommand
PS : You can bind to any event of any control. Like Closing event of Window and you will get the corresponding events.
通过 Blend for Visual Studio 2013 中的行为和操作,您可以使用 InvokeCommandAction。我尝试使用 Drop 事件执行此操作,尽管 XAML 中未指定 CommandParameter,但令我惊讶的是,执行操作参数包含 DragEventArgs。我认为其他事件也会发生这种情况,但尚未对其进行测试。
With Behaviors and Actions in Blend for Visual Studio 2013 you can use the InvokeCommandAction. I tried this with the Drop event and although no CommandParameter was specified in the XAML, to my surprise, the Execute Action parameter contained the DragEventArgs. I presume this would happen for other events but have not tested them.
我所做的是使用 InvokeCommandAction 将控件加载事件绑定到视图模型中的命令,在 Xaml 中给控件 ax:Name 并作为 CommandParameter 传递,然后在所述加载命令中挂钩视图模型处理程序直到我需要的事件获取事件参数。
What I do is to use InvokeCommandAction to bind the control loaded event to a command in the view model, give the control a x:Name in Xaml and pass as CommandParameter, then in said loaded command hook view model handlers up to the events where I need to get the event args.
这是 @adabyron 答案的一个版本,可以防止泄漏的
EventArgs
抽象。首先,修改后的
EventToCommandBehavior
类(现在是通用抽象类,并使用 ReSharper 代码清理进行格式化)。请注意新的GetCommandParameter
虚拟方法及其默认实现:接下来是隐藏
DragCompletedEventArgs
的示例派生类。有些人对将EventArgs
抽象泄漏到他们的视图模型程序集中表示担忧。为了防止这种情况,我创建了一个代表我们关心的值的界面。该接口可以存在于视图模型程序集中,并在 UI 程序集中进行私有实现:将命令参数转换为 IDragCompletedArgs,类似于 @adabyron 的答案。
Here is a version of @adabyron's answer that prevents the leaky
EventArgs
abstraction.First, the modified
EventToCommandBehavior
class (now a generic abstract class and formatted with ReSharper code cleanup). Note the newGetCommandParameter
virtual method and its default implementation:Next, an example derived class that hides
DragCompletedEventArgs
. Some people expressed concern about leaking theEventArgs
abstraction into their view model assembly. To prevent this, I created an interface that represents the values we care about. The interface can live in the view model assembly with the private implementation in the UI assembly:Cast the command parameter to
IDragCompletedArgs
, similar to @adabyron's answer.作为 @Mike Fuchs 答案的改编,这里有一个更小的解决方案。我正在使用
Fody.AutoDependencyPropertyMarker
来减少一些样板。类
EventArgs
XAML
ViewModel
As an adaption of @Mike Fuchs answer, here's an even smaller solution. I'm using the
Fody.AutoDependencyPropertyMarker
to reduce some of the boiler plate.The Class
The EventArgs
The XAML
The ViewModel