tags:

views:

126

answers:

5

Anyone have any have some code to make everything (or even all TextBoxes in a form) read-only all at once without having to set every control to read only individually?

A: 
this.Enabled = false;

Depends on what you doing really, you might want to consider putting the control within a panel and disabling that.

Paulie Waulie
+2  A: 

You should be able to write yourself a utility function to do this. You can iterate over the form’s controls and then each control’s child controls recursively. For example:

public static void SetEnableOnAllControls(Control parentControl, bool enable)
{
    parentControl.Enabled = enable;
    foreach (Control control in parentControl.Controls)
        SetEnableOnAllControls(control, enable);
}

[...]

// inside your form:
SetEnableOnAllControls(this, false);

This doesn’t take care of ToolStrips, which aren’t controls. You could write a separate, similar method for those.

Notice that the above disables the form itself too. If you don’t want that, try this:

public static void SetEnableOnAllChildControls(Control parentControl, bool enable)
{
    foreach (Control control in parentControl.Controls)
    {
        control.Enabled = enable;
        SetEnableOnAllChildControls(control, enable);
    }
}

If you really meant the ReadOnly property, which is only relevant for TextBoxes, try this:

public static void SetReadOnlyOnAllControls(Control parentControl, bool readOnly)
{
    if (parentControl is TextBoxBase)
        ((TextBoxBase) parentControl).ReadOnly = readOnly;
    foreach (Control control in parentControl.Controls)
        SetReadOnlyOnAllControls(control, readOnly);
}
Timwi
Could put an `else` into that last snippet: `TextBox` controls aren't containers.
Ben Voigt
+1, the most thorough answer.
rmx
down voting is a bad luck.
igor
+2  A: 

I haven't tested this, but it should work:

foreach (var textBox in this.Controls.OfType<TextBox>())
    textBox.ReadOnly = true;

Edit: This is not such a good solution it seems: see Timwi's comment.

rmx
The most correct. But requires .NET 3.5
abatishchev
① Doesn’t take nested controls into account, i.e. works only on the top-level controls; ② Should use `TextBoxBase` so that it affects other text-box-like controls too (e.g. `RichTextBox`).
Timwi
Good points Timwi, thanks.
rmx
+3  A: 

In Form:

if (_cached == null)
{
    _cached = new List<TextBox>();

    foreach(var control in Controls)
    {
        TextBox textEdit = control as TextBox;
        if (textEdit != null)
        {
            textEdit.ReadOnly = false;
            _cached.Add(textEdit);
        }
    }
} 
else
{
    foreach(var control in _cached)
    {            
        control .ReadOnly = false;
    }
}

Add recursion also (Controls can be placed into other controls (panels)).

igor
I think storing in a cache increases the performance. You'll however have to consider the allowing the user to refresh the cache. Your code also does not iterate through nested controls (like Textboxes placed inside Panels). Overall, it's a good solution.
Alex Essilfie
@Alex Essilfie I wrote: "Add recursion also" :), there is no any mentions about dynamic code creation to reset _cache (see "in Form" no out of Form). Thank you.
igor
+2  A: 

Write an extension method which gathers controls and child controls of specified type:

public static IEnumerable<T> GetChildControls<T>(this Control control) where T : Control
{
    var children = control.Controls.OfType<T>();
    return children.SelectMany(c => GetChildControls<T>(c)).Concat(children);
}

Gather TextBoxes on the form (use TextBoxBase to affect RichTextBox, etc - @Timwi's solution):

IEnumerable<TextBoxBase> textBoxes = this.GetChildControls<TextBoxBase>();

Iterate thru collection and set read-only:

private void AreTextBoxesReadOnly(IEnumerable<TextBoxBase> textBoxes, bool value)
{
    foreach (TextBoxBase tb in textBoxes) tb.ReadOnly = value;
}

If want - use caching - @igor's solution

abatishchev
+1 This seems the most reusable solution to me.
nikie