【问题标题】:How can I pass the event argument to a command using triggers?如何使用触发器将事件参数传递给命令?
【发布时间】:2012-11-13 23:12:56
【问题描述】:

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

clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity 

(有没有更好的命名空间来做这个?)

绑定它没什么大不了的,重要的是把那个 PopulatingEventArgs 参数传递给绑定的命令。

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

【问题讨论】:

  • 不要在问题标题中添加标签。请参阅this link 撰写好的标题;)

标签: c# events mvvm silverlight-4.0 icommand


【解决方案1】:

我尝试了 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>

...在我的用户控件中。

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

public void ShowDialog(object sender, ShowDialogEventArgs e) {

}

public void AppointmentEditing(object sender, AppointmentEditingEventArgs e) {

} 

到目前为止工作良好。

【讨论】:

  • 这很有帮助。
  • 太棒了!!这避免了子类化并允许使用命令作为来自代码隐藏的事件处理程序
  • 如果您不想在项目中使用外部(非 MS)库,这是一个不错且简单的解决方案。
  • public void ShowDialog(object sender, ShowDialogEventArgs e) { } 我的解决方案似乎无法理解ShowDialogEventArgs。我应该如何实现它?
【解决方案2】:

没有内置方法,所以我是这样做的:

经典的交互触发器是这样使用的:

<Button Content="I am a button">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <i:InvokeCommandAction Command="{Binding CommandWithNoArgs}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

我们无法通过绑定访问MouseEnter 事件的EventArgs,因此我们将不得不修改将其丢弃的部分。
碰巧,那块是InvokeCommandAction

“所以我们只是将它子类化并覆盖一个一直在等待我们的便捷方法”是我想写的。但是这个类是密封的。

所以我们将不得不继承它的父(抽象)类:TriggerAction&lt;DependencyObject&gt;

最基本的实现是:

public class InteractiveCommand : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
    }
}

parameter 就是你的EventArgs
但是等等,事情没那么简单,我们必须重现普通InvokeCommandAction 的行为。
通过Reflector,我反编译了(不过你可以去看看官方源码,我就是懒)。

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

这是完整的课程(仅限 WPF,请参阅 SilverLight 的编辑):

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
}

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

现在我们可以这样做了:

<Button Content="I am a button">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <local:InteractiveCommand Command="{Binding CommandWithEventArgs}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

以及背后的代码:

#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)
{
}

这是一个包装;)

编辑:对于 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
    }

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

【讨论】:

  • 我认为它开箱即用非常灵活,这导致编写各种扩展来支持我们认为基本的东西。
  • 刚刚尝试了您的代码,尽管我知道代码本身不起作用。 (它是从更好的地方复制/粘贴吗?)基本上从未分配过 CommandName ,因此 ResolveCommand 返回 null ,因此整个事情都不起作用。还有一些小问题,比如 base.WritePostscript();没有在基类中定义,但这并不重要
  • 好的,请使用经过验证的流式 sn-p 修改您的代码:pastie.org/5437478, pastie.org/5437483 再次感谢您,祝您有美好的一天!
  • @bonomo 我只在 WPF 中尝试过,很高兴看到您可以将其移植到 silverlight。
  • @bonomo 我搞砸了代码隐藏,我现在修好了。另外,我试过你的馅饼,它们也很好用。请注意,我原来的 ResolveCommand() 方法取自官方交互库。
猜你喜欢
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-20
  • 2015-04-11
  • 2017-04-29
  • 2010-09-11
  • 2021-05-20
相关资源
最近更新 更多