Nick LaMarca
Nick LaMarca

Reputation: 8188

Make all Controls on a Form read-only at once

Does anyone have a piece of code to make all Controls (or even all TextBoxes) in a Form which is read-only at once without having to set every Control to read-only individually?

Upvotes: 10

Views: 30435

Answers (7)

Roberto Armenio
Roberto Armenio

Reputation: 1

I just developed a recursive solution that handles any kind of Web Control, using a simple static method and ASP.NET polymorphysm.

/// <summary>
/// Handle "Enabled" property of a set of Controls (and all of the included child controls through recursivity)
/// By default it disable all, making all read-only, but it can also be uset to re-enable everything, using the "enable" parameter 
/// </summary>
/// <param name="controls">Set of controls to be handled. It could be the entire Page.Controls set or all of the childs of a given control (property "Controls" of any Control-derived class)</param>
/// <param name="enable">Desired value of the property "enable" of each control. </param>
public static void DisableControls(ControlCollection controls, bool enable = false)
{
    foreach (Control control in controls)
    {
        var wCtrl = control as WebControl;
        if (wCtrl != null)
        {
            wCtrl.Enabled = enable;
        }

        if (control.Controls.Count > 0)
            DisableControls(control.Controls, enable);
    }
}

/// <summary>
/// Enable a set of Controls (and all of the included child controls through recursivity).
/// Friendly name for DisableControls(controls, true), that achieve the same result.
/// </summary>
/// <param name="Controls">Set of controls to be handled. It could be the entire Page.Controls set or all of the childs of a given control (property "Controls" of any Control-derived class)</param>
public static void EnableControls(ControlCollection controls)
{
    DisableControls(controls, true);
}

This is tested and looks fairly fast (less than a millisecond in a web form with 25+ controls to be disabled).

If you prefer an extension method, i think it should be enough to change the solution as follows:

public static void DisableControls(this Control control, bool enable = false)
{
    foreach (Control ctrl in control.Controls)
    {
        var wCtrl = ctrl as WebControl;
        if (wCtrl != null)
        {
            wCtrl.Enabled = enable;
        }

        if (ctrl.Controls.Count > 0)
            ctrl.DisableControls(enable);
    }
}

public static void EnableControls(this Control control)
{
    control.DisableControls(true);
}

Upvotes: 0

CodeWizard
CodeWizard

Reputation: 31

I would use reflection to check to see if the generic Control object has an Enabled property.

private static void DisableControl(Control control)
{
    PropertyInfo enProp = control.GetType().GetProperty("Enabled");
    if (enProp != null)
    {
        enProp.SetValue(control, false, null);
    }

    foreach (Control ctrl in control.Controls)
    {
        DisableControl(ctrl);
    }
}

Upvotes: 3

abatishchev
abatishchev

Reputation: 100308

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

Upvotes: 6

garik
garik

Reputation: 5756

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)).

Upvotes: 5

Nobody
Nobody

Reputation: 4841

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.

Upvotes: 2

Timwi
Timwi

Reputation: 66594

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);
}

Upvotes: 4

Paulie Waulie
Paulie Waulie

Reputation: 1690

this.Enabled = false;

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

Upvotes: 2

Related Questions