1

Not sure if the title makes much sense, so here is the full context:

I'm coding in C#. I've made an app with several UserControls, each one with many textboxes and radiobuttons. All radiobuttons are placed in a panel in a set of 2, looking like this:

[ <label> O <radiobutton1text> O <radiobutton2text> ]

(while the first radiobutton have TabStop = true, and the second's TabStop = false)

When tabbing to such panel, only radiobutton1text is focused, and when hitting the LeftArrow key the radiobutton2text is selected. That's the desired outcome.

In order to make a UserControl load faster the second (and above) time, I'm not closing it but rather replacing it with a different UserControl each time the contents need to change. But this rises an issue: When UserControl X is open, then on top of it I open UserControl Y and then back to X, the textboxes and radiobuttons still have the contents from the first session of when I had UserControl X open for the first time. (I need the contents of textboxes and radiobuttons to be reset after replacing a UserControl).

So I made a function that loops through all controls and empties their contents. The problem is, when I uncheck the radiobuttons (and restore their TabStop state to true) in this function, the second radiobutton is tabbable after I check either one of them and then invoke the function, whereas it wasn't before going through this function.

The function:

        public void BackToMain(object sender, EventArgs e)
        {
            // Go through all controls and empty each TextBox, RichTextBox, RadioButton or ComboBox.
            int parentControlsCount = Controls.Count - 1;
            for (int i = parentControlsCount; i >= 0; i--)
            {
                if (Controls[i].HasChildren == true)
                {
                    int childrenControlsCount = Controls[i].Controls.Count - 1;
                    for (int j = childrenControlsCount; j >= 0; j--)
                    {
                        var controlType = Controls[i].Controls[j].GetType().ToString();

                        switch (controlType)
                        {
                            case "System.Windows.Forms.TextBox":
                            case "System.Windows.Forms.RichTextBox":
                                Controls[i].Controls[j].Text = null;
                                break;

                            case "System.Windows.Forms.RadioButton":
                                // Restore both properties to default value
                                ((RadioButton)Controls[i].Controls[j]).Checked = false;
                                if (j == 1)
                                    ((RadioButton)Controls[i].Controls[j]).TabStop = true;
                                else if (j == 2)
                                    ((RadioButton)Controls[i].Controls[j]).TabStop = false;
                                break;

                            case "System.Windows.Forms.ComboBox":
                                ((ComboBox)Controls[i].Controls[j]).SelectedIndex = -1;
                                break;
                        }
                    }
                }
            }
        }

What am I doing wrong?

Itiel
  • 13
  • 4
  • You should probably add a `Reset()` method to your UserControls that performs this operation *from the inside*, setting a pre-defined *initial state*. You just call this method when needed. Btw, your pseudo-recursive procedure needs a redesign in any case, if something similar is used somewhere else. – Jimi Nov 03 '19 at 12:19
  • @Jimi Well, this function _is_ from said UserControl. And I think the problem here is with the logic. Manually enabling TabStop for the first radiobutton means that when the user will click the second one (after running this function), the TabStop state for the first one won't change until the user will select it and then the second one again. At least that is what's happening here. Even knowing this, I can't think of a good countermeasure except maybe creating a CheckedChanged event and doing things from there. I'm not using this method elsewhere, but what is wrong it? – Itiel Nov 03 '19 at 13:46
  • You have already noticed that the TabStop *feature* is also handled somewhere else (not by you). A hint that this *clearing* procedure is not exactly state of the art has been given (btw, a method named `BackToMain`doesn't suggest an internal method, `GetType()`, used internally, neither). Test it with a Panel with 2 RadioButtons. In the `Panel.Leave` event, write: `radioButton1.Checked = false; radioButton2.Checked = false; radioButton1.TabStop = true; radioButton2.TabStop = false;`. Add to the Form a couple of focusable controls and press Tab. – Jimi Nov 03 '19 at 14:14

1 Answers1

0

I ended up applying this gross hack- a function on every second radiobutton's CheckedChange:

        private void DisableTabStopOnCheckedChange(object sender, EventArgs e)
        {
            // Assume the following STR:
            // 1. In any radiobutton panel, select any radiobutton (without ever invoking BackToMain function in the first post);
            // 2. Invoke the BackToMain function;
            // 3. In the same radiobutton panel as in step #1, click the second radiobutton.
            // Normally, without this function, if the user will now cycle through the controls using the Tab key, both the first and second radiobuttons will be tabbable,
            // and that's because in the BackToMain function we reset their Checked and TabStop properies, and that's something that should be handled automatically by the control itself.
            // Doing it manually means that for the *first time* selecting the second radiobutton, the first one's TabStop state won't update, which means both radiobuttons
            // will have the TabStop state set to true, causing both to be tabbable.
            // This is a gross hack to fix this by disabling TabStop on the first radio button if the second one is checked and the first one's TabStop state
            // is true (this should happen only after BackToMain has been invoked).
            if (((RadioButton)sender).Checked)
            {
                var firstRadioButton = ((RadioButton)sender).Parent.Controls[1];
                if (((RadioButton)firstRadioButton).TabStop == true)
                {
                    ((RadioButton)firstRadioButton).TabStop = false;
                }
            }
        }

Not a pretty solution, I know. But it works.

Itiel
  • 13
  • 4