如何使用触发器将事件参数传递给命令?

Tri*_*Gao 17 c# events mvvm icommand silverlight-4.0

所以我有一个简单的设置,一个带有Populating事件的自动完成框,我想绑定到一个命令.我用

clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity 
Run Code Online (Sandbox Code Playgroud)

(这有更好的命名空间吗?)

绑定它并不是什么大不了的事,最重要的是将PopulatingEventArgs参数传递给bound命令.

那么我该如何根据PRISM的最佳实践和MVVM一般来做呢?

Sea*_*ase 39

我尝试了InteractiveCommand,它给我带来了麻烦.相反,我设置了对Microsoft.Expression.Interactions的引用并包含在内

xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 

<i:Interaction.Triggers>
    <i:EventTrigger EventName="AppointmentEditing">
        <ei:CallMethodAction MethodName="AppointmentEditing" TargetObject="{Binding}" />
    </i:EventTrigger>
    <i:EventTrigger EventName="ShowDialog">
        <ei:CallMethodAction MethodName="ShowDialog" TargetObject="{Binding}" />
    </i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)

...在我的UserControl中.

然后将事件处理程序放在我的ViewModel中并将范围设置为public:

public void ShowDialog(object sender, ShowDialogEventArgs e) {

}

public void AppointmentEditing(object sender, AppointmentEditingEventArgs e) {

} 
Run Code Online (Sandbox Code Playgroud)

到目前为止运作良好.

  • 大!!这避免了子类化并允许使用命令作为代码隐藏的事件处理程序 (5认同)
  • 对我来说,这个应该是公认的答案 (4认同)
  • 这非常有帮助。 (2认同)

Lou*_*ann 25

没有内置方式,所以我这样做:

经典的Interaction触发器使用如下:

<Button Content="I am a button">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <i:InvokeCommandAction Command="{Binding CommandWithNoArgs}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>
Run Code Online (Sandbox Code Playgroud)

我们不能访问EventArgs的的MouseEnter通过有约束力的事件,所以我们将不得不修改扔它拿走一块.
碰巧的是,那件作品就是InvokeCommandAction.

"所以我们只是将它子类化并覆盖一直等待我们的方便方法"是我想写的.但课程是密封的.

所以我们必须继承它的父(抽象)类: TriggerAction<DependencyObject>

最基本的实现是:

public class InteractiveCommand : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

parameter是你的EventArgs!
但坚持下去,并不是那么简单,我们必须重现常规的行为InvokeCommandAction.
通过Reflector,我反编译它(但你可以去看官方消息来源,我只是懒惰).

我们不会关心CommandParameter依赖属性,我们假设如果你使用它而不是InvokeCommandAction,你实际上EventArgs每次都想要它.

这里是完整的类(仅限WPF,请参阅SilverLight的EDIT):

public class InteractiveCommand : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
        if (base.AssociatedObject != null)
        {
            ICommand command = this.ResolveCommand();
            if ((command != null) && command.CanExecute(parameter))
            {
                command.Execute(parameter);
            }
        }
    }

    private ICommand ResolveCommand()
    {
        ICommand command = null;
        if (this.Command != null)
        {
            return this.Command;
        }
        if (base.AssociatedObject != null)
        {
            foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal))
                {
                    command = (ICommand)info.GetValue(base.AssociatedObject, null);
                }
            }
        }
        return command;
    }

    private string commandName;
    public string CommandName
    {
        get
        {
            base.ReadPreamble();
            return this.commandName;
        }
        set
        {
            if (this.CommandName != value)
            {
                base.WritePreamble();
                this.commandName = value;
                base.WritePostscript();
            }
        }
    }

    #region Command
    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

与您从互联网上获取的任何代码一样,我强烈建议您阅读整个班级,并尝试了解它的作用.不要只是把它扔进你的应用程序.

现在我们可以做到:

<Button Content="I am a button">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <local:InteractiveCommand Command="{Binding CommandWithEventArgs}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>
Run Code Online (Sandbox Code Playgroud)

而背后的代码:

#region CommandWithEventArgs
DelegateCommand<MouseEventArgs> _CommandWithEventArgs;
/// <summary>
/// Exposes <see cref="CommandWithEventArgs(MouseEventArgs)"/>.
/// </summary>
public DelegateCommand<MouseEventArgs> CommandWithEventArgs
{
    get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<MouseEventArgs>(CommandWithEventArgs)); }
}
#endregion
public void CommandWithEventArgs(MouseEventArgs param)
{
}
Run Code Online (Sandbox Code Playgroud)

这是一个包装;)

编辑:对于SilverLight,请改用以下代码:

    public class InteractiveCommand : TriggerAction<DependencyObject>
    {
        protected override void Invoke(object parameter)
        {
            if (base.AssociatedObject != null)
            {
                ICommand command = Command;
                if ((command != null) && command.CanExecute(parameter))
                {
                    command.Execute(parameter);
                }
            }
        }

        #region Command
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
        #endregion
    }
Run Code Online (Sandbox Code Playgroud)

但请注意,它不如使用完整的WPF版本安全(不检查类型,可能会冻结冻结元素).