Как отключить все элементы управления в форме, кроме кнопки?

Моя форма содержит сотни элементов управления: меню, панели, разделители, метки, текстовые поля, которые вы называете.

Есть ли способ отключить каждый элемент управления, за исключением одной кнопки?

Причина, по которой кнопка важна, заключается в том, что я не могу использовать метод, который отключает окно или что-то, потому что один элемент управления все еще должен использоваться.

Ответ 1

Вы можете сделать рекурсивный вызов, чтобы отключить все задействованные элементы управления. Затем вам нужно включить свою кнопку и любые родительские контейнеры.

 private void Form1_Load(object sender, EventArgs e) {
        DisableControls(this);
        EnableControls(Button1);
    }

    private void DisableControls(Control con) {
        foreach (Control c in con.Controls) {
            DisableControls(c);
        }
        con.Enabled = false;
    }

    private void EnableControls(Control con) {
        if (con != null) {
            con.Enabled = true;
            EnableControls(con.Parent);
        }
    }

Ответ 2

На основе ответа @pinkfloydx33 и сделанного мной изменения я создал метод расширения, который делает его еще проще, просто создайте public static class следующим образом:

public static class GuiExtensionMethods
{
        public static void Enable(this Control con, bool enable)
        {
            if (con != null)
            {
                foreach (Control c in con.Controls)
                {
                    c.Enable(enable);
                }

                try
                {
                    con.Invoke((MethodInvoker)(() => con.Enabled = enable));
                }
                catch
                {
                }
            }
        }
}

Теперь, чтобы включить или отключить элемент управления, форму, меню, субконтроли и т.д. Просто выполните:

this.Enable(true); //Will enable all the controls and sub controls for this form
this.Enable(false);//Will disable all the controls and sub controls for this form

Button1.Enable(true); //Will enable only the Button1

Итак, что бы я сделал, аналогично @pinkfloydx33 Ответ:

private void Form1_Load(object sender, EventArgs e) 
{
        this.Enable(false);
        Button1.Enable(true);
}

Мне нравятся методы расширения, потому что они являются статическими, и вы можете использовать его везде, не создавая экземпляры (вручную), и это гораздо яснее, по крайней мере для меня.

Ответ 3

Для лучшего, более элегантного решения, которое было бы легко поддерживать - вам, вероятно, придется пересмотреть свой дизайн, например, оставить свою кнопку в стороне от других элементов управления. Затем, предполагая, что другие элементы управления находятся в панели или групповом ящике, просто выполните Panel.Enabled = False.

Если вы действительно хотите сохранить свой текущий дизайн, вы можете линеаризовать дерево ControlCollection в массив Control, чтобы избежать рекурсии, а затем выполните следующие действия:

Array.ForEach(Me.Controls.GetAllControlsOfType(Of Control), Sub(x As Control) x.Enabled = False)
yourButton.Enabled = True

Ответ 4

Когда у вас много вложенных панелей или таблиц TableLayoutPanels, ситуация становится сложной. Попытка отключить все элементы управления на панели, отключив родительскую панель и затем включив дочерний элемент управления, вообще не включает этот элемент управления, поскольку родительский (или родительский) родительский элемент не включен. Чтобы оставить включенным нужный дочерний элемент управления, я видел макет формы в виде дерева с самой формой в качестве корня, любой контейнер или панель в виде ветвей, а дочерние элементы управления (кнопки, надписи, метки и т.д.) - в виде конечных узлов. Итак, основная цель - отключить все узлы на том же уровне, что и требуемый элемент управления, взбираясь по дереву элементов управления до уровня формы, устанавливая путь включенных элементов управления, чтобы дочерний элемент мог работать:

public static void DeshabilitarControles(Control control)
{
    if (control.Parent != null)
    {
        Control padre = control.Parent;
        DeshabilitarControles(control, padre);
    }
}

private static void DeshabilitarControles(Control control, Control padre)
{
    foreach (Control c in padre.Controls)
    {
        c.Enabled = c == control;
    }
    if (padre.Parent != null)
    {
        control = control.Parent;
        padre = padre.Parent;
        DeshabilitarControles(control, padre);
    }
}

public static void HabilitarControles(Control control)
{
    if (control != null)
    {
        control.Enabled = true;
        foreach (Control c in control.Controls)
        {
            HabilitarControles(c);
        }
    }
}

Ответ 5

Я исправил ответ @coloboxp. Сначала необходимо включить всех родителей:

    public static void Enable(this Control con, bool enable)
    {
        if (con != null)
        {
            if (enable)
            {
                Control original = con;

                List<Control> parents = new List<Control>();
                do
                {
                    parents.Add(con);

                    if (con.Parent != null)
                        con = con.Parent;
                } while (con.Parent != null && con.Parent.Enabled == false);

                if (con.Enabled == false)
                    parents.Add(con); // added last control without parent

                for (int x = parents.Count - 1; x >= 0; x--)
                {
                    parents[x].Enabled = enable;
                }

                con = original;
                parents = null;
            }

            foreach (Control c in con.Controls)
            {
                c.Enable(enable);
            }

            try
            {
                con.Invoke((MethodInvoker)(() => con.Enabled = enable));
            }
            catch
            {
            }
        }
    }