Invoke Command When “ENTER” Key Is Pressed In XAML

后端 未结 5 454
花落未央
花落未央 2020-12-24 08:38

I want to invoke a command when ENTER is pressed in a TextBox. Consider the following XAML:



        
5条回答
  •  猫巷女王i
    2020-12-24 08:57

    I like scottrudy's approach (to which I've given a +1) with the custom triggers approach as it stays true to my initial approach. I'm including a modified version of it below to use dependency properties instead of reflection info so that it's possible to bind directly to the ICommand. I'm also including an approach using attached properties to avoid using System.Windows.Interactivity if desired. The caveat to the latter approach is that you lose the feature of multiple invokations from an event, but you can apply it more generally.


    Custom Triggers Approach

    ExecuteCommandAction.cs

    public class ExecuteCommandAction : TriggerAction {
        #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);
            }
        }
    }
    

    TextBoxEnterKeyTrigger.cs

    public class TextBoxEnterKeyTrigger : TriggerBase {
        protected override void OnAttached() {
            base.OnAttached();
            TextBox textBox = this.AssociatedObject as TextBox;
    
            if (textBox != null) {
                this.AssociatedObject.KeyUp += new System.Windows.Input.KeyEventHandler(AssociatedObject_KeyUp);
            }
            else {
                throw new InvalidOperationException("This behavior only works with TextBoxes");
            }
        }
    
        protected override void OnDetaching() {
            base.OnDetaching();
            AssociatedObject.KeyUp -= new KeyEventHandler(AssociatedObject_KeyUp);
        }
    
        private void AssociatedObject_KeyUp(object sender, KeyEventArgs e) {
            if (e.Key == Key.Enter) {
                TextBox textBox = AssociatedObject as TextBox;
    
                //This checks for an mvvm style binding and updates the source before invoking the actions.
                BindingExpression expression = textBox.GetBindingExpression(TextBox.TextProperty);
                if (expression != null)
                    expression.UpdateSource();
    
                InvokeActions(textBox.Text);
            }
        }
    }
    

    MyUserControl.xaml

    
            
                
                    
                
            
        
        ...
    
    

    Attached Properties Approach

    EnterKeyDown.cs

    public sealed class EnterKeyDown {
    
        #region Properties
    
        #region Command
    
        public static ICommand GetCommand(DependencyObject obj) {
            return (ICommand)obj.GetValue(CommandProperty);
        }
    
        public static void SetCommand(DependencyObject obj, ICommand value) {
            obj.SetValue(CommandProperty, value);
        }
    
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EnterKeyDown),
                new PropertyMetadata(null, OnCommandChanged));
    
        #endregion Command
    
        #region CommandArgument
    
        public static object GetCommandArgument(DependencyObject obj) {
            return (object)obj.GetValue(CommandArgumentProperty);
        }
    
        public static void SetCommandArgument(DependencyObject obj, object value) {
            obj.SetValue(CommandArgumentProperty, value);
        }
    
        public static readonly DependencyProperty CommandArgumentProperty =
            DependencyProperty.RegisterAttached("CommandArgument", typeof(object), typeof(EnterKeyDown),
                new PropertyMetadata(null, OnCommandArgumentChanged));
    
        #endregion CommandArgument
    
        #region HasCommandArgument
    
    
        private static bool GetHasCommandArgument(DependencyObject obj) {
            return (bool)obj.GetValue(HasCommandArgumentProperty);
        }
    
        private static void SetHasCommandArgument(DependencyObject obj, bool value) {
            obj.SetValue(HasCommandArgumentProperty, value);
        }
    
        private static readonly DependencyProperty HasCommandArgumentProperty =
            DependencyProperty.RegisterAttached("HasCommandArgument", typeof(bool), typeof(EnterKeyDown),
                new PropertyMetadata(false));
    
    
        #endregion HasCommandArgument
    
        #endregion Propreties
    
        #region Event Handling
    
        private static void OnCommandArgumentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            SetHasCommandArgument(o, true);
        }
    
        private static void OnCommandChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            FrameworkElement element = o as FrameworkElement;
            if (element != null) {
                if (e.NewValue == null) {
                    element.KeyDown -= new KeyEventHandler(FrameworkElement_KeyDown);
                }
                else if (e.OldValue == null) {
                    element.KeyDown += new KeyEventHandler(FrameworkElement_KeyDown);
                }
            }
        }
    
        private static void FrameworkElement_KeyDown(object sender, KeyEventArgs e) {
            if (e.Key == Key.Enter) {
                DependencyObject o = sender as DependencyObject;
                ICommand command = GetCommand(sender as DependencyObject);
    
                FrameworkElement element = e.OriginalSource as FrameworkElement;
                if (element != null) {
                    // If the command argument has been explicitly set (even to NULL)
                    if (GetHasCommandArgument(o)) {
                        object commandArgument = GetCommandArgument(o);
    
                        // Execute the command
                        if (command.CanExecute(commandArgument)) {
                            command.Execute(commandArgument);
                        }
                    }
                    else if (command.CanExecute(element.DataContext)) {
                        command.Execute(element.DataContext);
                    }
                }
            }
        }
    
        #endregion
    }
    

    MyUserControl.xaml

    
        ...
    
    

提交回复
热议问题