C# 如何禁用窗体上除按钮外的所有控件?

C# 如何禁用窗体上除按钮外的所有控件?,c#,winforms,controls,C#,Winforms,Controls,我的表单有数百个控件:菜单、面板、拆分器、标签、文本框,你可以随意选择 是否有一种方法可以禁用除单个按钮之外的所有控件 按钮之所以重要,是因为我无法使用禁用窗口的方法或其他方法,因为一个控件仍然需要可用。您可以执行递归调用以禁用所有涉及的控件。然后必须启用按钮和任何父容器 private void Form1_Load(object sender, EventArgs e) { DisableControls(this); EnableControls(Butt

我的表单有数百个控件:菜单、面板、拆分器、标签、文本框,你可以随意选择

是否有一种方法可以禁用除单个按钮之外的所有控件


按钮之所以重要,是因为我无法使用禁用窗口的方法或其他方法,因为一个控件仍然需要可用。

您可以执行递归调用以禁用所有涉及的控件。然后必须启用按钮和任何父容器

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

为了获得更好、更优雅、易于维护的解决方案,您可能需要重新考虑您的设计,例如将按钮与其他控件放在一起。然后假设其他控件位于面板或组框中,只需执行
panel.Enabled=False

如果确实希望保留当前设计,可以避免递归,然后执行以下操作:

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

基于@pinkfloydx33的答案和我对它所做的编辑,我创建了一个扩展方法,使它更加容易,只需创建一个
公共静态类
,如下所示:

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

我喜欢扩展方法,因为它们是静态的,您可以在任何地方使用它,而无需(手动)创建实例,而且至少对我来说更清楚。

当您有许多面板或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);
        }
    }
}

我已更正@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
            {
            }
        }
    }
publicstaticvoid启用(此控件为con,bool启用)
{
如果(con!=null)
{
如果(启用)
{
控制原始=con;
列表父项=新列表();
做
{
添加(con);
如果(con.Parent!=null)
con=con.父母;
}while(con.Parent!=null&&con.Parent.Enabled==false);
如果(con.Enabled==false)
parents.Add(con);//添加了最后一个没有父控件的控件
对于(int x=parents.Count-1;x>=0;x--)
{
父项[x]。已启用=启用;
}
con=原件;
父母=空;
}
foreach(控制中的控制c)
{
c、 使能(使能);
}
尝试
{
con.Invoke((MethodInvoker)(()=>con.Enabled=enable));
}
抓住
{
}
}
}

是否应将按钮放在单独的表单中?是否可以循环浏览表单上的所有控件,并在每个控件上设置Enabled属性?在循环中,使用按钮的ID/名称忽略该按钮。或者,继续禁用循环中的所有内容,然后立即启用按钮。为什么要在其中包含ref关键字?我不会。我在打电话的时候,不知什么原因,它才出来。做得好。我喜欢你如何使方法不知道或不关心任何具体的控制。新手们忽略了这类事情。@Hi Angel:递归调用是必要的,因为Winforms中的父/子关系是递归的。在许多表单中,只有一个级别的子体,因此不需要递归,但需要一个好的通用解决方案,以便它在所有情况下都能工作,而不仅仅是在您测试的情况下。如果您想重新启用表单,这是行不通的。如果您调用DisableControls(此);然后调用EnableControls(this),它将只启用窗体,而不启用任何子控件…+1 for
Panel.Enabled=false | true
。重新设计界面,创建一组控件,然后禁用整个组,这无疑是设计UI的更好方法。这行不通。如果您将其命名为.Enable(false);然后调用Button1.Enable(true),那么这个(表单)和Button1的任何其他父控件仍然被禁用。可能我不理解你的意思,但我认为这就是重点。尝试启用Button1的父控件。如果需要,它应该启用父控件及其所有子控件。