3
votes

I have been trying to debug a form for about 15 hours and have finally discovered what the problem is. It appears that all NumericUpDown controls have an associated TextBox control which is unnamed. My problem can be reproduced as follows:

  1. Create a new project with a single form
  2. Put a button, a TextBox and a NumericUpDown on the form
  3. Use the following code in the form

    private int testing = 0;
    public Form1()
    {
        InitializeComponent();
    }
    
    
    private void Form1_Load(object sender, EventArgs e)
    {
        Mytest(this);
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        NumericUpDown nud;
        foreach (Control c in this.Controls)
        {
            if (c is TextBox)
            {
                c.Text = "that";
            }
            if (c is NumericUpDown)
            {
                nud = c as NumericUpDown;
                nud.Value = 0;
            }
    
        }
    }
    private void TestEmpty(Control ctl)
    {
        foreach (Control c in ctl.Controls)
        {
            if (c is TextBox && c.Name == "")
            {
                ++testing;
                c.BackColor = Color.Red;
                c.Text = "Something";
            }
            TestEmpty(c);
        }
    }
    private void Mytest(Control ctl)
    {
        TestEmpty(this);
    
        MessageBox.Show("Found " + testing.ToString() + " items");
    }
    
  4. Assign the form's load event and the button's click event to the handlers in the code

  5. Run the form

Initially, the NumericUpDown control contains the text "Something". If you click the button, the new value of 0 is not assigned.

If, however, you assign a nnon-zero value to the NumericUpDown Value property in the button's click event:

nud.Value = 42;

the button works as expected.

After any text has been assigned to the unnamed Text Box associated with the NumericUpdown control, it is not possible to assign a value of zero to the NumericUpDown.

I am using recursive code like this in a number of places to populate and reset forms. Now that I know where the problem lies, I can work around it by checking for an unnamed TextBox:

if (c is TextBox && c.Name != "")

but this seems very ugly and potentially error-prone.

Have I misunderstood something? Is there a cleaner way to handle these spuriously TextBoxes when looping through controls?

1
I have edited your title. Please see, "Should questions include “tags” in their titles?", where the consensus is "no, they should not".John Saunders
Can you please explain in plain text what you want to achieve?Sandy
@rapsalands The code above just demonstrated the problem. In the actual application, I reset a form by looping through the controls and setting TextBoxes to "" and NumericUpDowns to their minimum value (usually zero). I cannot do this because setting all text boxes to "" preevebts me from setting NumericUpDowns to zero.Blind Fury

1 Answers

3
votes

After any text has been assigned to the unnamed Text Box associated with the NumericUpdown control, it is not possible to assign a value of zero to the NumericUpDown.

That's not quite right.

What's happening is that the Value of the NumericUpDown is currently at Zero (because that's the initial Value when you dropped it on the Form), but the Text property displays otherwise. Underneath, though, the Value is still zero.

When you attempt to "reset" the NumericUpDown, you assign Zero to it...but the Value is already Zero (underneath the hood), so it doesn't refresh itself (why would it?..under normal operation it's impossible to have non-numeric text displayed inside it). This is evident if you change the value to the Maximum() first, then back to the Minimum():

                nud = c as NumericUpDown;
                nud.Value = nud.Maximum;
                nud.Value = nud.Minimum; 

Assuming the Min and Max are not the same number, this will force the NumericUpDown to refresh itself and display the zero.

Now, you can prevent this problem by simply not recursing into the control if it's a TextBox or a NumericUpdown, which are the controls you're interested in resetting. A simple rewrite:

    private void Reset(Control ctl)
    {
        foreach (Control c in ctl.Controls)
        {
            if (c is TextBox)
            {
                c.Text = "";
            }
            else if (c is NumericUpDown)
            {
                NumericUpDown nud = c as NumericUpDown;
                nud.Value = nud.Minimum;
            }
            else if (c.HasChildren)
            { 
                Reset(c);
            }
        }
    }