如何使用触发器将事件参数传递给命令? [英] How can I pass the event argument to a command using triggers?

查看:261
本文介绍了如何使用触发器将事件参数传递给命令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个简单的设置,一个自动填充框,其Populating事件我想绑定到一个命令。我使用

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

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



不是一个很大的约束力,最重要的是将PopulatingEventArgs参数传递给绑定的命令。



那么如何根据PRISM的最佳做法特别的和MVVM一般?

解决方案

没有内置的方式,所以这里是我如何做:



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

 < Button Content = 我是一个按钮> 
< i:Interaction.Triggers>
< i:EventTrigger EventName =MouseEnter>
< i:InvokeCommandAction Command ={Binding CommandWithNoArgs}/>
< / i:EventTrigger>
< / i:Interaction.Triggers>
< / Button>

我们无法访问 EventArgs 通过绑定的 MouseEnter 事件,所以我们将不得不修改将其抛弃的部分。

正因为如此,这件作品是 InvokeCommandAction



所以我们只是去分类它,并覆盖一直在等待我们的方便的方法是我想写的。但是这个类是密封的。



所以我们要把它的父类(抽象)类子类: TriggerAction< DependencyObject>



最基本的实现是:

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

参数是您的 EventArgs

但坚持下来,这不是那么简单,我们必须重现一个常规的 InvokeCommandAction 的行为。

通过反射器,我反编译它(但你可以去看看官方消息来源,我只是懒惰)。



我们不会在乎code CommandParameter 依赖属性,我们假设如果使用这个而不是 InvokeCommandAction ,那么您实际上需要 EventArgs

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

  public class InteractiveCommand:TriggerAction< DependencyObject> 
{
protected override void Invoke(object parameter)
{
if(base.AssociatedObject!= null)
{
ICommand命令= 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命令
public ICommand Command
{
get {return(ICommand)GetValue CommandProperty); }
set {SetValue(CommandProperty,value); }
}

//使用DependencyProperty作为Command的后备存储。这使得动画,样式,绑定等...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(Command,typeof(ICommand),typeof(InteractiveCommand),new UIPropertyMetadata(null)) ;
#endregion
}

与从互联网获取的任何代码一样, 我非常推荐阅读整个班级,并试图了解它的作用。不要把它折腾到你的应用程序中。



现在我们可以做:

 < Button Content =我是一个按钮> 
< i:Interaction.Triggers>
< i:EventTrigger EventName =MouseEnter>
< local:InteractiveCommand Command ={Binding CommandWithEventArgs}/>
< / i:EventTrigger>
< / i:Interaction.Triggers>
< / Button>

后面的代码:

  #region CommandWithEventArgs 
DelegateCommand< MouseEventArgs> _CommandWithEventArgs;
///< summary>
///暴露< 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 =
if((command!= null)&& command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}

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

//使用DependencyProperty作为Command的后备存储。这使得动画,样式,绑定等...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(Command,typeof(ICommand),typeof(InteractiveCommand),new UIPropertyMetadata(null)) ;
#endregion
}

但请注意,它比使用安全性更低完整的WPF版本(不检查类型,可能与冻结元素崩溃)。


So I have a simple setup, an autocompletebox with its Populating event that I want to bind to a command. I use

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

(is there a better namespace for doing this?)

It's not a big deal to bind it, the big deal is to pass that PopulatingEventArgs argument to the bound command.

So how do I do it according to the best practices of PRISM in particular and MVVM in general?

解决方案

There is no built-in way, so here is how I do it:

The classic Interaction trigger is used like this:

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

We can't access the EventArgs of the MouseEnter event through binding, so we're going to have to modify the piece that tosses it away.
As it happens, that piece is the InvokeCommandAction.

"So we're just going to subclass it and override a convenient method that was waiting for us all along" is what I'd have liked to write. But the class is sealed.

So we're going to have to subclass its parent (abstract) class: TriggerAction<DependencyObject>

The most basic implementation is:

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

And that parameter is your EventArgs!
But hold on, it's not that simple, we have to reproduce the behavior of a regular InvokeCommandAction.
Through Reflector, I decompiled it (but you could go look at the official source, I'm just lazy).

We're not going to care about the CommandParameter dependency property, we're going to assume that if you use this instead of InvokeCommandAction, you actually want the EventArgs every time.

Here goes the full class (WPF only, see EDIT for 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
}

As with any code you fetch from the internet, I highly recommand reading through the whole class, and trying to understand what it does. Don't just toss it into your app.

Now we can do:

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

And the code behind:

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

And that's a wrap ;)

EDIT: For SilverLight, use this code instead:

    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
    }

But please note that it is less safe than using the full fledged WPF version (doesn't check types, can crash with frozen elements).

这篇关于如何使用触发器将事件参数传递给命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆