【问题标题】:KeyBinding with Command Binding dont work with TextBox UpdateSourceTrigger LostFocus带有命令绑定的 KeyBinding 不适用于 TextBox UpdateSourceTrigger LostFocus
【发布时间】:2014-04-19 20:16:23
【问题描述】:

我正在使用 MVVM 并遇到以下问题。我的 TextBox.Text 与 UpdateSourceTrigger=LostFocus 绑定(这就是用户想要的)。我有一个带有 SaveCommand CommandBinding 的按钮 - 这很有效。现在我有一个带有 Strg+S 的 KeyBinding,它也执行 SaveCommand。这就是问题所在:当我在文本框中按 Strg+s 时,更改不在视图模型中。

有没有办法让 MVVM 命令与 KeyBinding 和 TextBox UpdateSourceTrigger=LostFocus 一起工作?

一些代码来检查问题

<Window>
<Window.InputBindings>
    <KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveCommand}"></KeyBinding>
</Window.InputBindings>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>      
    <TextBox Grid.Row="0" Text="{Binding MyText1, UpdateSourceTrigger=LostFocus}" Width="100"></TextBox>
    <Button Grid.Row="1" Content="_Save" Command="{Binding SaveCommand}" IsDefault="True"></Button> 
</Grid>
</Window>

public partial class MainWindow : Window
{
    private Viewmodel _data;
    public MainWindow()
    {
        _data = new Viewmodel();
        InitializeComponent();
        this.DataContext = _data;
    }
}

public class Viewmodel : INPCBase
{
    private string _myText1;
    private Lazy<DelegateCommand> _save;

    public Viewmodel()
    {
        this._save = new Lazy<DelegateCommand>(()=> new DelegateCommand(this.SaveCommandExecute));
    }

    private void SaveCommandExecute()
    {
        MessageBox.Show(MyText1);
    }

    public string MyText1
    {
        get { return _myText1; }
        set { _myText1 = value; this.NotifyPropertyChanged(()=>MyText1);}
    }

    public ICommand SaveCommand
    {
        get { return _save.Value; }
    }
}

【问题讨论】:

  • > UpdateSourceTrigger=LostFocus(这就是用户想要的),MyText1 属性是否有任何附加功能已更改?当您更新绑定 Source 时用户如何看到?
  • 每个文本框都有验证,用户不希望在离开文本框之前看到任何验证错误

标签: wpf mvvm key-bindings updatesourcetrigger


【解决方案1】:

目前我想出了以下解决方法。在我定义我的 KeyBindings 的用户控件/视图中,我还监听 PreviewKeyDown 事件并将焦点设置到下一个元素,例如。 Strg+S 被按下。

    private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.S && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
        {
            var fe = Keyboard.FocusedElement as UIElement;

            if (fe != null)
            {
               fe.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }

        }
    }

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,最终得到了 TextBox 的附加属性。

    public static bool GetCommitOnSave(DependencyObject obj)
    {
        return (bool)obj.GetValue(CommitOnSaveProperty);
    }
    
    public static void SetCommitOnSave(DependencyObject obj, bool value)
    {
        obj.SetValue(CommitOnSaveProperty, value);
    }
    
    public static readonly DependencyProperty CommitOnSaveProperty =
        DependencyProperty.RegisterAttached("CommitOnSave", typeof(bool), typeof(Helper), new PropertyMetadata(false, CommitOnSavePropertyChanged));
    
    private static void CommitOnSavePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox textBox)
        {
            if ((bool)e.NewValue)
            {
                if ((bool)e.NewValue)
                {
                    textBox.KeyDown += TextBox_KeyDown;
                }
                else
                {
                    textBox.KeyDown -= TextBox_KeyDown;
                }
            }
        }
    }
    
    private static void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        var textBox = (TextBox)sender;
        if (e.Key == Key.S && Keyboard.Modifiers == ModifierKeys.Control)
        {
            BindingOperations.GetBindingExpression(textBox, TextBox.TextProperty).UpdateSource();
        }
    }
    

    使用&lt;TextBox Text="{Binding Name}" local:Helper.CommitOnSave="True" /&gt;

    当然,您可以为表单中的所有 TextBox 设置样式中的附加属性。

    【讨论】:

      【解决方案3】:

      我想我找到了最适合我的解决方案。我将解决方案 @blindmeis 和我以前的解决方案与使用附加属性混合在一起。

      我创建了更新实际键盘焦点元素的绑定源的命令:

      public class CommitValueCommand : ICommand
      {
          private static CommitValueCommand _instance;
          public static CommitValueCommand Command => _instance ?? (_instance = new CommitValueCommand());
      
          public event EventHandler CanExecuteChanged;
      
          public bool CanExecute(object parameter)
          {
              return true;
          }
      
          public void Execute(object parameter)
          {
              if (Keyboard.FocusedElement is TextBox textBox)
              {
                  BindingOperations.GetBindingExpression(textBox, TextBox.TextProperty).UpdateSource();
              }
              //for combobox etc.
              else if (Keyboard.FocusedElement is Selector selector)
              {
                  BindingOperations.GetBindingExpression(selector, Selector.SelectedValueProperty).UpdateSource();
              }
          }
      }
      

      在命令SaveCommand的Execute方法中刚刚开始调用CommitValueCommand.Command.Execute()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-03
        • 1970-01-01
        • 1970-01-01
        • 2011-07-26
        • 1970-01-01
        • 2014-10-27
        • 1970-01-01
        • 2023-03-07
        相关资源
        最近更新 更多