4

How can we change the ReadOnly property of all textBoxes in a winform that is true to false i'm trying using this code but this prompt me object null reference error...

    private void TextBoxesReadOnlyTrue(Control.ControlCollection cc)
    {
        foreach (Control ctrl in cc)
        {
            TextBox tb = ctrl as TextBox;
            if (tb.ReadOnly)
             {
                tb.ReadOnly = false;
             }

        }
    } 
buddy
  • 418
  • 4
  • 10
  • 29

2 Answers2

6

That's because not all the controls in cc are TextBoxes. So when you try converting them to a TextBox, the variable is null. When a variable is null, you cannot access any properties on that variable, or you'll get an error. So anytime a variable can be null, you MUST first test whether it is null.

Here's the modified if command that you'll want to use to fix your problem:

    if (tb != null && tb.ReadOnly) { tb.ReadOnly = false; }

So i appologize that i overlooked that your TextBoxes can be contained in other container controls. Yes, that means you need to do 1 of 2 things: 1: You can move the TextBoxes outside the GroupBox. haha. I'm just joking. Yes, that can solve that problem but then you have worse problems. The correct way is to recursively call your method for every control that has controls in its Controls property. Every control has this property but it seems it is empty (but not null) in controls that are not containers. (I just learned today that every control has this Controls property, so i've updated my code to reflect this.) So for this real solution, i suggest something similar to this:

private void TextBoxesReadOnlyTrue(Control.ControlCollection cc)
{
    foreach (Control ctrl in cc)
    {
        TextBox tb = ctrl as TextBox;
        if (tb != null && tb.ReadOnly)
        { tb.ReadOnly = false; continue; }

        if (ctrl.Controls != null && ctrl.Controls.Count > 0)
        { TextBoxesReadOnlyTrue(ctrl.Controls); }
        // this recursively calls this same method for every control ...
        // that is a container control that contains more controls, ...
        // such as GroupBoxes, Panels, etc.
    }
}
Shawn Kovac
  • 1,425
  • 15
  • 17
  • Not Working!how ever now it is not prompting the error. is it due to the textboxes are laying in a groupbox? – buddy Oct 30 '13 at 02:44
  • @buddy, yes, TextBoxes being in a GroupBox is an additional complication, which would cause my original answer to be lacking. my bad. I've updated my answer to give you 2 options to fix this new issue. all you really need to do is add 2 lines of code. :) – Shawn Kovac Oct 30 '13 at 13:57
2

first you would like to use a function like this:

Recursive get controls

then you do the following

private IEnumerable<T> GetControls<T>(Control.ControlCollection ctrls)
{
    foreach (object ctrl in ctrls)
    {
        foreach (var item in GetControls<T>(((Control)ctrl).Controls))
        {
            yield return item;    
        } 
        if (ctrl is T)
           yield return (T)ctrl;

    }
}

foreach(var txtbox in  GetControls<TextBox>(form.Controls)
{
    txtbox.ReadOnly = false;
}
Community
  • 1
  • 1
Stig
  • 1,323
  • 16
  • 22
  • Stig, i like your answer too. This is complicated for some, but for those who understand this code, it's very useful. So I thank you for your (very) good solution, and i up-voted you for it too. I also gave a more basic C# solution that is easier to follow, for those who want the simple way without complicating it too. In this case, i don't see any need to use this lazy-loading with `yield`, but i expect there are sometimes when this solution would be better than the alternative simple solution i gave. But to each his own (or her own). Happy coding, all! – Shawn Kovac Oct 30 '13 at 14:01