Silverlight 调用命令时";输入“;键在XAML中按下

Silverlight 调用命令时";输入“;键在XAML中按下,silverlight,xaml,eventtrigger,invoke-command,Silverlight,Xaml,Eventtrigger,Invoke Command,当在文本框中按ENTER键时,我想调用一个命令。考虑下面的XAML: <UserControl ... xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" ...> ... <TextBox> <i:Interaction.Triggers>

当在
文本框中按ENTER键时,我想调用一个命令。考虑下面的XAML:

<UserControl
     ...
     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
     ...>    
     ...    
     <TextBox>
          <i:Interaction.Triggers>
               <i:EventTrigger EventName="KeyUp">
                    <i:InvokeCommandAction Command="{Binding MyCommand}"
                                           CommandParameter="{Binding Text}" />
               </i:EventTrigger>
          </i:Interaction.Triggers>
     </TextBox>    
     ...    
</UserControl>

...    
...    
我的命令如下:

public ICommand MyCommand {
     get { return new DelegateCommand<string>(MyCommandExecute); }
}

private void MyCommandExecute(string s) { ... }
public ICommand MyCommand{
获取{returnnewdelegatecommand(MyCommandExecute);}
}
私有void MyCommandExecute(字符串s){…}
通过以上步骤,每次按键都会调用我的命令。如何将命令限制为仅在按下ENTER键时调用

< P>我知道,使用表达式混合,我可以使用条件,但那些似乎只限于元素,不能考虑事件参数。
我还遇到过这样一个例子,它提供了自己的
InvokeCommandAction
实现,它构建在
Systems.Windows.Interactivity
实现之上,可以做我需要的事情。另一个考虑是编写自己的触发器,但我希望有一种不用外部工具包就能完成的方法

在我脑海中。。您可以将事件参数传递给命令,然后在ViewModel中检查e.KeyPress=Keys。输入。。这不是真正的代码:)我没有我的VS在这台计算机上。。这是一个想法:)

我昨天遇到了同样的问题,并使用自定义触发器解决了它。一开始可能看起来有点多,但我发现这个通用模式可以用来做很多事情,我曾经在视图中直接使用事件处理程序来完成这些事情(比如双击事件)。第一步是创建一个可以接受参数的触发器操作,因为我们以后需要它

public class ExecuteCommandAction : TriggerAction<FrameworkElement>
{
    public string Command { get; set; }

    protected override void Invoke(object o)
    {
        if (Command != null)
        {
            object ctx = AssociatedObject.DataContext;
            if (ctx != null)
            {
                var cmd = ctx.GetType().GetProperty(Command)
                    .GetValue(ctx, null) as ICommand;
                if (cmd != null && cmd.CanExecute(o))
                {
                    cmd.Execute(o);
                }
            }
        }
    }
}
公共类ExecuteCommandAction:TriggerAction
{
公共字符串命令{get;set;}
受保护的覆盖无效调用(对象o)
{
if(命令!=null)
{
对象ctx=AssociatedObject.DataContext;
如果(ctx!=null)
{
var cmd=ctx.GetType().GetProperty(命令)
.GetValue(ctx,null)作为ICommand;
如果(cmd!=null&&cmd.CanExecute(o))
{
命令执行(o);
}
}
}
}
}
下一步是创建触发器。您可以使用基类做一些有趣的事情,使其更通用,以捕获不同类型的按键,但我们将保持简单

public class TextBoxEnterKeyTrigger: TriggerBase<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.KeyUp += AssociatedObject_KeyUp;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
    }

    void AssociatedObject_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            TextBox textBox = AssociatedObject as TextBox;
            object o = textBox == null ? null : textBox.Text;
            if (o != null)
            {
                InvokeActions(o);
            }
        }
    }
}
公共类TextBoxEnterKeyTrigger:TriggerBase
{
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.KeyUp+=AssociatedObject\u KeyUp;
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
AssociatedObject.KeyUp-=AssociatedObject\u KeyUp;
}
无效关联对象\u KeyUp(对象发送方,System.Windows.Input.KeyEventArgs e)
{
如果(e.Key==Key.Enter)
{
TextBox TextBox=关联对象为TextBox;
对象o=textBox==null?null:textBox.Text;
如果(o!=null)
{
调用(o);
}
}
}
}
请记住,即使您的TextBox值有数据绑定,属性更改事件也不会触发,因为您的TextBox没有失去焦点。因此,我将TextBox.Text属性的值传递给命令。最后一步是在XAML中使用此功能。您需要确保包括交互性名称空间以及包含上面代码的名称空间

<UserControl
...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:common="clr-namespace:My.UI;assembly=My.UI">
    <TextBox Text="{Binding Path=MyText, Mode=TwoWay}" IsEnabled="{Binding CanMyCommand}">
        <i:Interaction.Triggers>
            <common:TextBoxEnterKeyTrigger>
                <common:ExecuteCommandAction Command=MyCommand" />
            </common:TextBoxEnterKeyTrigger>
        </i:Interaction.Triggers>
    </TextBox>
</UserControl>


我喜欢scottrudy的方法(我给了它+1)和自定义触发器方法,因为它与我最初的方法保持一致。我在下面添加了它的一个修改版本,使用依赖属性而不是反射信息,这样就可以直接绑定到ICommand。我还包括一种使用附加属性的方法,以避免在需要时使用
System.Windows.Interactivity
。后一种方法需要注意的是,您失去了一个事件的多个调用功能,但您可以更普遍地应用它


自定义触发器方法

ExecuteCommandAction.cs

public class ExecuteCommandAction : TriggerAction<DependencyObject> {
    #region Properties
    public ICommand Command {
        get { return (ICommand)base.GetValue(CommandProperty); }
        set { base.SetValue(CommandProperty, value); }
    }

    public static ICommand GetCommand(DependencyObject obj) {
        return (ICommand)obj.GetValue(CommandProperty);
    }

    public static void SetCommand(DependencyObject obj, ICommand value) {
        obj.SetValue(CommandProperty, value);
    }

    // We use a DependencyProperty so we can bind commands directly rather
    // than have to use reflection info to find them
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(ExecuteCommandAction), null);
    #endregion Properties

    protected override void Invoke(object parameter) {
        ICommand command = Command ?? GetCommand(AssociatedObject);
        if (command != null && command.CanExecute(parameter)) {
            command.Execute(parameter);
        }
    }
}
MyUserControl.xaml

<UserControl
    ...
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:b="clr-namespace:MyNameSpace.Interactivity"
    ...
    <TextBox>
        <i:Interaction.Triggers>
            <b:TextBoxEnterKeyTrigger>
                <b:ExecuteCommandAction Command="{Binding MyCommand}" />
            </b:TextBoxEnterKeyTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    ...
</UserControl>
<UserControl
    ...
    xmlns:b="clr-namespace:MyNameSpace.Interactivity"
    ...
    <TextBox b:EnterKeyDown.Command="{Binding AddNewDetailCommand}"
             b:EnterKeyDown.CommandArgument="{Binding Path=Text,RelativeSource={RelativeSource Self}}" />
    ...
</UserControl>

我在应用程序中使用了scottrudy的代码,但是,我的文本框文本绑定到viewmodel类中的某个属性,并且在按ENTER键后调用命令时,该属性不会得到更新,因为我的文本框尚未失去焦点。所以,为了解决这个问题,我在AssociatedObject_KeyUp方法的InvokeActions(o)上方添加了以下代码片段,更新的文本属性在viewmodel类中得到更新

                    BindingExpression bindingExpression = (textBox).GetBindingExpression(TextBox.TextProperty);
                bindingExpression.UpdateSource();
在表达上存在着交融

<UserControl
xmlns:i="clr-namespace:System.Windows.Interactivity;
         assembly=System.Windows.Interactivity"
xmlns:iex="clr-namespace:Microsoft.Expression.Interactivity.Input;
           assembly=Microsoft.Expression.Interactions" ...>    
     <TextBox>
         <i:Interaction.Triggers>
            <iex:KeyTrigger Key="Enter">
               <i:InvokeCommandAction Command="{Binding PasswordLoginCommand}" />
            </iex:KeyTrigger>
         </i:Interaction.Triggers>
     </TextBox>    
</UserControl>


System.Windows.Interactivity
Microsoft.Expression.Interactivity
程序集可用于官方的WPF。

这并不比挂接文本框的KeyUp或KeyPress事件,并在事件处理程序中调用命令(如果e.Key==ENTER)要好。所以,这需要命令避免的紧密耦合……我要求用XAML解决这个问题;检查ViewModel中的键只需添加另一个层来处理具有代码隐藏的事件,这可以在视图(而不是视图模型)中轻松完成。此外,这样的事件处理无论如何都不应该发生在视图模型中=)+1的自定义触发器方法中-我在回答中与另一种方法一起对其进行了修改。有趣。。我在ExecuteCommandAction上遇到了问题,并加入了I:InvokeCommandAction,因为我无论如何都有引用,它工作得很好。我只是想说,这是解决我问题的一个很好的方法。非常感谢:)我现在有一个问题,当我按enter键时,值还没有设置,命令得到ex
                    BindingExpression bindingExpression = (textBox).GetBindingExpression(TextBox.TextProperty);
                bindingExpression.UpdateSource();
<UserControl
xmlns:i="clr-namespace:System.Windows.Interactivity;
         assembly=System.Windows.Interactivity"
xmlns:iex="clr-namespace:Microsoft.Expression.Interactivity.Input;
           assembly=Microsoft.Expression.Interactions" ...>    
     <TextBox>
         <i:Interaction.Triggers>
            <iex:KeyTrigger Key="Enter">
               <i:InvokeCommandAction Command="{Binding PasswordLoginCommand}" />
            </iex:KeyTrigger>
         </i:Interaction.Triggers>
     </TextBox>    
</UserControl>