【问题标题】:Preventing WPF form submit on pressing Enter key防止在按 Enter 键时提交 WPF 表单
【发布时间】:2016-11-18 14:26:19
【问题描述】:

我有一个 WPF XAML 屏幕,其中包含多个控件(文本框、组合框、按钮等)。后面的代码在 C# 中。我为其中一个按钮保留了IsDefault="True"。因此,如果用户在任何文本框中按下 Enter 键,表单就会被提交。

我只需要为一个特定的文本框使用 Enter 键提交表单。如果用户在任何其他文本框中按 Enter 键,我不希望提交表单。

我知道我可以使用后面的代码(即*.xaml.cs)来实现这一点。但是如何使用 MVVM 设计模式来实现这一点呢?

【问题讨论】:

  • 创建附加行为,该行为将连接适当的键事件以处理回车键。
  • 嗯,这是代码隐藏的工作,因为这是视图逻辑。

标签: c# wpf xaml mvvm


【解决方案1】:

您可能并不关心用户在哪个文本框中输入,您只希望完成整个表单。如果是这种情况,请使用您的绑定执行验证并禁用该按钮。

public ICommand SaveCommand
{
    get
    {
        if (_saveCommand == null)
            _saveCommand = new RelayCommand(x => Save(), CanSave);

        return _saveCommand;
    }
}

private void CanSave(object sender)
{
    // Validate properties, ensure viewmodel is in savable state.

    // Maybe you implemented IDataErrorInfo?
    if (Validator.TryValidateObject(this, new ValidationContext(this, null, null), new List<ValidationResult>(), true))
        return true;
    else
        return false;
}

private void Save()
{
    // Database stuff, maybe WCF stuff, etc.
}

【讨论】:

  • 感谢 FrumRoll 提供的 cmets。但正如我所提到的,只有当用户在一个特定的文本框中按下回车键时,我才需要提交表单(比如说 txtboxProductKey)。表单提交不应该被任何其他触发文本框,无论用户是否在 txtboxProductKey 中输入了值。
  • @Vineetv 您当然可以验证所有绑定值,而不仅仅是 ProductKey。但是,如果您只想使用单个文本框来触发命令,我会从您的按钮中删除 IsDefault="True",然后简单地将命令绑定到文本框。
【解决方案2】:

您可以将 Button 的 IsDefault 属性绑定到允许的 TextBox 的 IsFocused 属性,如下所示。

    <TextBox x:Name="TB1" Grid.Row="0" Height="15" Width="300">

    </TextBox>
    <TextBox x:Name="TB2" Grid.Row="1" Height="15" Width="300">

    </TextBox>
    <Button Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Height="40" Width="200" Content="Button"
            IsDefault="{Binding IsFocused, ElementName=TB2}"  Click="Button_Click">
    </Button>

我有它,所以 IsEnabled 属性已绑定,但它阻止了按钮单击工作。然后我尝试根据 TB2 或 Button 的焦点对其进行多重绑定,但如果 TB1 获得焦点,这仍然会阻止点击,因为禁用的按钮无法接受点击获取焦点。

【讨论】:

    【解决方案3】:

    只需在您要处理的文本框上设置AcceptsReturn="True" 输入自己而不是路由到表单。

    【讨论】:

    • 这可行,但会将文本框变成多行文本框。有什么办法可以防止吗?
    • 据我所知,在 Windows 8/10 上 MaxLines 属性无法正常工作。我认为您可能不得不求助于带有吞下按键的键盘事件处理程序的派生控件。
    【解决方案4】:

    您可以从按钮中删除 IsDefault="True" 并将您的命令绑定到文本框本身。在 StackOverflow 上有很多方法可以做到这一点。我的偏好是使用自定义文本框。

    public class CommandTextBox : TextBox, ICommandSource
    {
        private bool _canExecute;
        private EventHandler _canExecuteChanged;
    
        protected override bool IsEnabledCore
        {
            get 
            {
                if (Command != null)
                    return base.IsEnabledCore && _canExecute;
    
                return base.IsEnabledCore;
            }
        }
    
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandTextBox), new PropertyMetadata(OnCommandChanged));
    
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    
        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandTextBox));
    
        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
    
        public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CommandTextBox));
    
        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }
    
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);
    
            if (e.Key == Key.Enter)
            {
                if (Command != null)
                {
                    RoutedCommand command = Command as RoutedCommand;
    
                    if (command != null)
                        command.Execute(CommandParameter, CommandTarget);
                    else
                        Command.Execute(CommandParameter);
                }
    
                e.Handled = true;
            }
        }
    
        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);
        }
    
        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);
        }
    
        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CommandTextBox)d).HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
        }
    
        private void RemoveCommand(ICommand command)
        {
            EventHandler handler = CanExecuteChanged;
            command.CanExecuteChanged -= handler;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-28
      • 2010-10-09
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2022-01-06
      • 1970-01-01
      相关资源
      最近更新 更多