1

I have a TextBox for which I would like to run through a few conditions based on whether or not there is an integer entered in it. My operations take place from the code-behind of the window that the TextBox exists in.

Under the LostFocus event I would like to do the following:

  • Check if the string IsNullOrEmpty

    -If it is - set text to "Default Record"

  • Verify that the entered value is an Int

    If it isn't - Display a MessageBox(Ok Button), then set focus back on the TextBox

**This is what my LostFocus function looks like:

private void TextBox_LostFocus(object sender, RoutedEventArgs e) //Lost Focus
{
    if (string.IsNullOrEmpty(TextBox.Text))
        TextBox.Text = "Default Record";
    else if (Regex.IsMatch(TextBox.Text, @"^\d+$") == false)
    {
        MessageBox.Show("Illegal character in list.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning);
        TextBox.Focus();
    }
}

The above function works well for testing whether or not the string IsNullOrEmpty, but I'm having problems with the else if condition. When I try to reset the focus back onto the TextBox I get an endless loop of MessageBoxes. Why is this and how do I fix it?

Update 1:

These are additional event handlers on the TextBox:

//State of View at startup
private void Document_Loaded(object sender, RoutedEventArgs e)
{
    //This is run because I need the TextBox to have focus at window startup
    TextBox.Focusable = true;
    TextBox.Focus();
}

xaml:

<UserControl Loaded="Document_Loaded" ... >
Eric after dark
  • 1,768
  • 4
  • 31
  • 79
  • 1
    Do you have any other event handlers on the textbox, or any code not shown in this handler? – Servy Nov 12 '13 at 21:14
  • Yes, I have plenty. It's kind of a lot if I were to post all of it. What should I be looking for that would mess up this process? – Eric after dark Nov 12 '13 at 21:17
  • @Ericafterdark, `other event handlers on the textbox`. – Mike Perrenoud Nov 12 '13 at 21:18
  • 2
    @Ericafterdark start removing them one by one until you come up with the smallest code sample needed to replicate the problem. When you are to the point where removing any of the remaining event handlers, or removing any sections of the existing handlers, causes the program to no longer replicate the problem then you have your "minimal reproducible code sample". In many cases, by the time you get to that point, the problem is obvious. If it's not, edit the question to include it. – Servy Nov 12 '13 at 21:19
  • What event of `Textbox` is `Document_Loaded` a handler for? – Servy Nov 12 '13 at 21:21
  • @Servy That is actually the `Loaded` event of the UserControl that the `TextBox` is located in – Eric after dark Nov 12 '13 at 21:21
  • Perhaps a `GotFocus` event for the `TextBox`? – ispiro Nov 12 '13 at 21:22
  • @ispiro Are you saying use that instead? Because I still need this `TextBox` to have focus at startup. – Eric after dark Nov 12 '13 at 21:23
  • @Ericafterdark No, he's asking if there is a got focus event handler. If there were, and it did something to lose focus, then the answer would be clear; each handler fires the other, forever. – Servy Nov 12 '13 at 21:24
  • @Ericafterdark No. I'm saying perhaps you are subscribing to that event and that event handler is causing a LostFocus. – ispiro Nov 12 '13 at 21:24
  • There is no `GotFocus` handler on the `TextBox`. There is a `MouseEnter` and a `MouseLeave`, but these should not be interfering in anyway. – Eric after dark Nov 12 '13 at 21:26
  • Would it matter that the `Text` in the box is bound to a `string` property in a data model? – Eric after dark Nov 12 '13 at 21:28
  • Then I go back to my previous comment. Start removing stuff until you get to the smallest program you can make that replicates the problem, or if easier, make a new project and copy over as little as you possibly can to replicate the problem. When you have done so, post that code here so that we can replicate the problem. – Servy Nov 12 '13 at 21:28
  • @ispiro That also requires those mouse events to remove focus from the textbox. – Servy Nov 12 '13 at 21:31
  • 1
    Okay, I've created a brand new program that contains a window with 2 `TextBoxes`. The only event handler in this whole window is the `LostFocus` one that you see above. With that being said, I receive the same infinite loop of `MessageBoxes`. Maybe you can't call `.focus()` from a `LostFocus` event handler... – Eric after dark Nov 12 '13 at 21:34
  • 1
    I am able to replicate it (sort of - it only happens 3 times~). (Winforms) Strange. – ispiro Nov 12 '13 at 21:42

4 Answers4

1

Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers. Doing so can cause your application or the operating system to stop responding...

From MSDN

ispiro
  • 26,556
  • 38
  • 136
  • 291
  • Then how am I ever supposed to base these actions off of the user leaving the `TextBox`? – Eric after dark Nov 12 '13 at 21:57
  • @Ericafterdark You aren't. That's the point. Regardless, it's really poor user design to prevent them from removing focus from the textbox until it's fixed. Just prevent them from performing any actions that depend on that textbox having a valid value (i.e. disable related buttons) instead of forcing focus on the textbox. – Servy Nov 12 '13 at 21:58
  • @Servy I gotcha. I'll have to redesign a little, but it makes sense. – Eric after dark Nov 12 '13 at 22:00
0

When I try to reset the focus back onto the TextBox I get an endless loop of MessageBoxes

This happens because you're invoking the focus to the TextBox control, just when the event LostFocus is raised. When you close the MessageBox, the TextBox control got the focus, but the event LostFocus is continuously raised, and, because the else condition is satisfied, you will have an endless loop with the MessageBoxes.

I think you shouldn't use the event LostFocus to check the value of the TextBox and focus again. Have you considered the event TextChanged ?

You could then do something like this:

private void TextTest_TextChanged(object sender, TextChangedEventArgs e)
{
      Console.WriteLine("Text changed");

      /*  your logic here */   

      TextTest.Focus(); //it could be useless in this case!
}
Alberto Solano
  • 7,972
  • 3
  • 38
  • 61
  • Where it says `your logic here`, do I have to change anything? – Eric after dark Nov 12 '13 at 21:40
  • 1
    First, this won't cause a stack overflow exception. The stack is not increasing. It just goes forever. Next, the code shown doesn't indicate how setting focus results in the focus being lost again, which needs to happen for there to be an infinite loop. – Servy Nov 12 '13 at 21:40
  • @Servy Yes, you're right. I tested a wrong piece of code. My fault. My answer is updated. – Alberto Solano Nov 12 '13 at 21:49
  • @Ericafterdark You should replace the comment with your logic, used to check the input of the user in your TextBox. – Alberto Solano Nov 12 '13 at 21:50
  • @AlbertoSolano It's still not right. If you set focus whenever focus is lost then you can never focus anything else (which, granted, is poor user design) but unless focusing the object again results in focus being lost, the "lost focus" handler isn't fired a second time, so there is no looping. The looping isn't inherent in the code that is shown. – Servy Nov 12 '13 at 21:52
  • @Servy I understood, but it's very strange anyway. I tested the code shown in the first part in the question with a simple app, and I have the same problem of the user. – Alberto Solano Nov 12 '13 at 21:57
0

Keep track of whether the value has changed since you last showed the message box. Only show the messagebox if the value has changed since you last showed the message box.

I think like this:

private string lastValue = null;
private void TextBox_LostFocus(object sender, RoutedEventArgs e) //Lost Focus
{
    bool valueChanged = ( lastvalue != TextBox.Text );
    lastValue = TextBox.Text;
    if (string.IsNullOrEmpty(TextBox.Text))
        TextBox.Text = "Default Record";
    else if (Regex.IsMatch(TextBox.Text, @"^\d+$") == false && valueChanged )
    {
        MessageBox.Show("Illegal character in list.", "Warning!", MessageBoxButton.OK, MessageBoxImage.Warning);
        TextBox.Focus();
    }
}
Derek
  • 7,615
  • 5
  • 33
  • 58
0

You may also want to look at using a masked textbox to limit the input to integers. Then you want to do the validation (checking) when the user hits "ok/next/submit"... whatever will finish the entry.

http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.mask%28v=vs.90%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

Derek
  • 7,615
  • 5
  • 33
  • 58