【问题标题】:WPF & MVVM: passing event args don't workWPF & MVVM:传递事件参数不起作用
【发布时间】:2017-02-24 11:57:56
【问题描述】:

我有 WPF MVVM 应用程序,我想将事件 args 传递到 ViewModel 中,但它不起作用。我浏览了在这个网站和其他网站上找到的大量类似主题,但没有结果。

这是我在控件中的 XAML:

<telerik:RadMap>
<i:Interaction.Triggers>
  <i:EventTrigger EventName="MouseMove" >
    <ei:CallMethodAction TargetObject="{Binding}" MethodName="VM.SomeMethod"/>
  </i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadMap>

在我的 ViewModel 中,我有方法:

public void SomeMethod(object sender, MouseEventArgs e)
{

}

当我将鼠标移到控件上时,它会引发异常,指出该方法没有适当的签名。

然后我也尝试使用telerik的EventToCommandBehavior,像这样:

<telerik:RadMap>
<telerik:EventToCommandBehavior ...>
...

它抱怨 EventToCommandBehavior 不存在。我用谷歌搜索,甚至在 Telerik 文档中也发现了这个 EventToCommandBehavior。所以我猜测这可能是一个较新的功能,因为我的 Telerik 是从 2010 年开始的。

无论如何,欢迎任何关于如何将事件参数传递给 ViewModel 的建议。

【问题讨论】:

  • 使用EventToCommand 时,您需要在ViewModel 上添加Binding to ICommandThis 可能会有所帮助!
  • 如果删除“VM.”会怎样:MethodName="SomeMethod"?
  • 我从未使用过 Telerik 的 mvvm 框架,但如果它像 MVVM Light 一样工作,则需要设置一个名为 PassEventArgsToCommand 的属性。

标签: c# wpf mvvm


【解决方案1】:

编辑:我应该更好地阅读这个问题。绑定表达式的默认根是被绑定的 UI 元素的 DataContext,因此绑定表达式将 VM.SomeCommand 读取为 DataContext.VM.SomeCommand。 VM.SomeCommand 应该更改为只是 SomeCommand,因为您的视图的 DataContext 应该是您的 ViewModel。

Expression Blend 交互性框架不支持将事件参数传递给命令。我建议使用 MVVM 框架。

使用 Bradley Uffner 提到的 MVVM Light,您可以这样做:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="MouseMove">
        <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=SomeCommand}"
                            PassEventArgsToCommand="True" />
    </i:EventTrigger>
</i:Interaction.Triggers>

但是,如果您出于某种原因反对该想法,您可以尝试here 讨论的解决方案。

链接中的示例代码:

public sealed class InvokeDelegateCommandAction : TriggerAction<DependencyObject>
{
    /// <summary>
    /// 
    /// </summary>
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(InvokeDelegateCommandAction), null);

    /// <summary>
    /// 
    /// </summary>
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
        "Command", typeof(ICommand), typeof(InvokeDelegateCommandAction), null);

    /// <summary>
    /// 
    /// </summary>
    public static readonly DependencyProperty InvokeParameterProperty = DependencyProperty.Register(
        "InvokeParameter", typeof(object), typeof(InvokeDelegateCommandAction), null);

    private string commandName;

    /// <summary>
    /// 
    /// </summary>
    public object InvokeParameter
    {
        get
        {
            return this.GetValue(InvokeParameterProperty);
        }
        set
        {
            this.SetValue(InvokeParameterProperty, value);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public ICommand Command
    {
        get
        {
            return (ICommand)this.GetValue(CommandProperty);
        }
        set
        {
            this.SetValue(CommandProperty, value);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public string CommandName
    {
        get
        {
            return this.commandName;
        }
        set
        {
            if (this.CommandName != value)
            {
                this.commandName = value;
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public object CommandParameter
    {
        get
        {
            return this.GetValue(CommandParameterProperty);
        }
        set
        {
            this.SetValue(CommandParameterProperty, value);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="parameter"></param>
    protected override void Invoke(object parameter)
    {
        this.InvokeParameter = parameter;

        if (this.AssociatedObject != null)
        {
            ICommand command = this.ResolveCommand();
            if ((command != null) && command.CanExecute(this.CommandParameter))
            {
                command.Execute(this.CommandParameter);
            }
        }
    }

    private ICommand ResolveCommand()
    {
        ICommand command = null;
        if (this.Command != null)
        {
            return this.Command;
        }
        var frameworkElement = this.AssociatedObject as FrameworkElement;
        if (frameworkElement != null)
        {
            object dataContext = frameworkElement.DataContext;
            if (dataContext != null)
            {
                PropertyInfo commandPropertyInfo = dataContext
                    .GetType()
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .FirstOrDefault(
                        p =>
                        typeof(ICommand).IsAssignableFrom(p.PropertyType) &&
                        string.Equals(p.Name, this.CommandName, StringComparison.Ordinal)
                    );

                if (commandPropertyInfo != null)
                {
                    command = (ICommand)commandPropertyInfo.GetValue(dataContext, null);
                }
            }
        }
        return command;
    }
}

来自博客的示例用法:

<ComboBox>
    <ComboBoxItem Content="Foo option 1" />
    <ComboBoxItem Content="Foo option 2" />
    <ComboBoxItem Content="Foo option 3" />
    <Interactivity:Interaction.Triggers>
        <Interactivity:EventTrigger EventName="SelectionChanged" >
            <Presentation:InvokeDelegateCommandAction 
                Command="{Binding SubmitFormCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=InvokeParameter}" />
        </Interactivity:EventTrigger>
    </Interactivity:Interaction.Triggers>                
</ComboBox>

注意:我尚未测试此博客中的解决方案。

【讨论】:

    【解决方案2】:

    来自this,我读到了

    被调用的方法必须是不带参数且不返回值的公共方法或签名与事件处理程序的签名匹配的公共方法。

    如果你不是特别需要MouseEventArgs信息,你可以尝试不带参数,或者带:

    public void SomeMethod(object sender, EventArgs e)
    {
    
    }
    

    我的 2 美分...

    【讨论】:

    • 您的 2 美分在最初的主题中被提及,并确认它不起作用
    • 我在你的帖子中看到的和我建议的区别在于事件参数的类型,在你的情况下是MouseEventArgs,在我的情况下只是EventArgs。是你试过的吗?问题是,可能使用 MouseEventArg 限制性太强,预期类型只是 EventArgs,您可以稍后在事件管理中将其转换回 MouseEventArgs
    猜你喜欢
    • 2017-02-27
    • 1970-01-01
    • 2023-03-19
    • 2016-09-22
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    相关资源
    最近更新 更多