【问题标题】:Binding a WPF TextBox events to commands [duplicate]将 WPF 文本框事件绑定到命令 [重复]
【发布时间】:2015-01-08 11:46:44
【问题描述】:

我正在尝试找到一个关于如何将一些 TextBox 事件(PreviewTextInput 和 PreviewKeyDown)绑定到命令的简单示例,但是我找不到任何明确的示例,并且到目前为止我发现的所有示例都强制我使用一些 MVVM框架(Light 工具包、Prism 等),但目前我不想使用框架,因为我想更深入地了解业务的运作方式。

  1. 谁能提供一个简单的例子来说明如何实现这一点?
  2. 一定要使用 MVVM 框架吗?

提前致谢。

【问题讨论】:

    标签: wpf mvvm routed-commands


    【解决方案1】:

    简单的方法是将通用事件处理程序附加到 XAML 中的事件,并在代码隐藏中调用命令。这样的事件处理程序可能如下所示:

    private void TextBox_OnTextChanged(object sender, EventArgs e)
    {
        var viewmodel = this.DataContext as MyViewmodel;
        if (viewmodel != null)
        {
            viewmodel.SomeCommand.Execute();
        }
    }
    

    在代码隐藏中不使用任何代码的替代方法(但实现起来有点棘手,并且仅适用于 .NET 4.5)是实现您自己的 MarkupExtension,这样您就可以编写类似的代码

    <TextBox TextChanged="{myMarkupExtension:CommandBinding SomeCommand]">...</TextBox>
    

    有几篇文章描述了这种方法,例如this one

    【讨论】:

    • 谢谢,但我想明白,这不能用 和 EventTrigger 来实现吗?
    【解决方案2】:

    你可以继承TextBox并实现ICommandSource。我也做了同样的事情,我的实现看起来像这样。您应该能够扩展它以在 PreviewTextInput 上工作。

    public class CommandTextBox : TextBox, ICommandSource
    {
        private bool _canExecute;
        private EventHandler _canExecuteChanged;
    
        /// <summary>
        /// DependencyProperty for Command property.
        /// </summary>
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandTextBox), new PropertyMetadata(OnCommandChanged));
    
        /// <summary>
        /// Gets or sets the command to invoke when the enter key is pressed.
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    
        /// <summary>
        /// DependencyProperty for CommandParameter property.
        /// </summary>
        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandTextBox));
    
        /// <summary>
        /// Gets or sets the parameter to pass to the Command property.
        /// </summary>
        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets a value that indicates whether the command resets the text property.
        /// </summary>
        public bool CommandResetsText { get; set; }
    
        /// <summary>
        /// DependencyProperty for CommandTarget property.
        /// </summary>
        public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CommandTextBox));
    
        /// <summary>
        /// Gets or sets the element on which to raise the specified command.
        /// </summary>
        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }
    
        /// <summary>
        /// Gets a value that becomes the return value of
        /// System.Windows.UIElement.IsEnabled in derived classes.
        /// </summary>
        protected override bool IsEnabledCore
        {
            get { return base.IsEnabledCore && _canExecute; }
        }
    
        /// <summary>
        /// Command dependency property change callback. 
        /// </summary>
        /// <param name="d">Dependency Object</param>
        /// <param name="e">Event Args</param>
        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CommandTextBox tb = (CommandTextBox)d;
            tb.HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
        }
    
        /// <summary>
        /// If Command is defined, pressing the enter key will invoke the command; 
        /// Otherwise, the textbox will behave normally. 
        /// </summary>
        /// <param name="e">Provides data about the event.</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
    
            if (e.Key == Key.Enter && Command != null)
            {
                RoutedCommand command = Command as RoutedCommand;
    
                if (command != null)
                    command.Execute(CommandParameter, CommandTarget);
                else
                    Command.Execute(CommandParameter);
    
                if (CommandResetsText)
                    this.Text = String.Empty;
            }
        }
    
        /// <summary>
        /// Add a command to the Command Property. 
        /// </summary>
        /// <param name="command">Command</param>
        private void AddCommand(ICommand command)
        {
            var handler = new EventHandler(CanExecuteChanged);
            _canExecuteChanged = handler;
            if (command != null)
                command.CanExecuteChanged += _canExecuteChanged;
        }
    
        private void CanExecuteChanged(object sender, EventArgs e)
        {
            if (Command != null)
            {
                RoutedCommand command = Command as RoutedCommand;
    
                // If a RoutedCommand. 
                if (command != null)
                    _canExecute = command.CanExecute(CommandParameter, CommandTarget);
                else
                    _canExecute = Command.CanExecute(CommandParameter);
            }
    
            CoerceValue(UIElement.IsEnabledProperty);
        }
    
        /// <summary>
        /// Add a new command to the Command Property. 
        /// </summary>
        /// <param name="oldCommand">Old Command</param>
        /// <param name="newCommand">New Command</param>
        private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
        {
            // If oldCommand is not null, then we need to remove the handlers. 
            if (oldCommand != null)
                RemoveCommand(oldCommand);
    
            AddCommand(newCommand);
        }
    
        /// <summary>
        /// Remove a command from the Command Property. 
        /// </summary>
        /// <param name="command">Command</param>
        private void RemoveCommand(ICommand command)
        {
            EventHandler handler = CanExecuteChanged;
            command.CanExecuteChanged -= handler;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-06-11
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      • 2011-06-21
      • 2017-09-04
      • 2010-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多