What's the best way to prevent losing TextBox focus when there is a validation error?

前端 未结 3 401
不思量自难忘°
不思量自难忘° 2021-02-04 20:44

I\'ve messed around with PreviewLostKeyboardFocus which almost gets you there. I\'ve seen a couple of implementations using LostFocus, but that just f

相关标签:
3条回答
  • 2021-02-04 20:53

    If you attempt to focus an element inside its own LostFocus handler you will face a StackOverflowException, I'm not sure about the root cause (I suspect the focus kind of bounces around) but there is an easy workaround: dispatch it.

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        var element = (sender as TextBox);
        if (!theTextBoxWasValidated())
        {
            // doing this would cause a StackOverflowException
            // element.Focus();
            var restoreFocus = (System.Threading.ThreadStart)delegate { element.Focus(); };
            Dispatcher.BeginInvoke(restoreFocus);
        }
    }
    

    Through Dispatcher.BeginInvoke you make sure that restoring the focus doesn't get in the way of the in-progress loss of focus (and avoid the nasty exception you'd face otherwise)

    0 讨论(0)
  • 2021-02-04 21:09

    In my opinion, the best way is generally not to do it. It is almost always better to just disable the other controls or prevent saving until the value is valid.

    But if your design really needs this ability, here is what you should do:

    1. Intercept the Preview version of keyboard and mouse events at your window level, or whatever scope you want to prevent focus changes within (eg maybe not your menu bar).

    2. When the Tab KeyDown or Return KeyDown is detected in the text box, or when a MouseDown is detected outside the text box while it has the focus, call UpdateSource() on the binding expression, then if the validation has failed set Handled=true to prevent the KeyDown or MouseDown event from being processed further.

    3. Also continue handling PreviewLostKeyboardFocus to catch any causes of focus change that aren't from the keyboard or mouse, or that your other code didn't recognize.

    0 讨论(0)
  • 2021-02-04 21:11

    To add onto Ray's answer:

    UpdateSource is called like so:

    BindingExpression be = userTextbox.GetBindingExpression(TextBox.TextProperty);
    be.UpdateSource();
    

    Also, as an alternative you can set the text box binding to:

    UpdateSourceTrigger = "PropertyChanged";
    

    The latter will cause a continuous check, whereas the former will check when needed (performant).

    0 讨论(0)
提交回复
热议问题