如何禁用表单上除按钮之外的所有控件?

Posted

技术标签:

【中文标题】如何禁用表单上除按钮之外的所有控件?【英文标题】:How to disable all controls on the form except for a button? 【发布时间】:2012-11-06 22:07:46 【问题描述】:

我的表单有数百个控件:菜单、面板、拆分器、标签、文本框,应有尽有。

有没有办法禁用除单个按钮之外的所有控件?

按钮很重要的原因是因为我不能使用禁用窗口或其他东西的方法,因为一个控件仍然需要可用。

【问题讨论】:

是否应该将按钮放在单独的表单中? 你不能循环遍历表单上的所有控件,在每个控件上设置 Enabled 属性吗?在您的循环中,使用其 ID/名称忽略该按钮。或者,继续禁用循环中的所有内容,然后立即启用按钮。 【参考方案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);
        
    

【讨论】:

为什么要在其中包含 ref 关键字? 我不会。我在打字时正在打电话,由于某种原因它刚刚出来 哈。做得好。我喜欢你如何让方法不知道或不关心任何特定的控件。新手会忽略这样的事情。 @Hi-Angel:递归调用是必要的,因为 Winforms 中的父/子关系是递归的。在许多形式中,只有一层后代,因此不需要递归,但需要一个好的通用解决方案,以便它适用于所有情况,而不仅仅是您测试的那个。 如果您想重新启用表单,这不起作用。如果你调用 DisableControls(this);然后调用 EnableControls(this) 它只会启用表单而不是任何子控件...【参考方案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);

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

【讨论】:

这不起作用。如果你调用 this.Enable(false);然后调用 Button1.Enable(true),然后 this(表单)和 Button1 的任何其他父控件仍然被禁用。 可能我不明白你的意思,但我认为这就是重点。如果您需要,请尝试启用 Button1 的父控件,它应该启用父控件及其所有子控件。【参考方案3】:

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

如果你真的想保留你当前的设计,你可以Linearise ControlCollection tree into array of Control来避免递归,然后执行以下操作:

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

【讨论】:

+1 表示Panel.Enabled = false|true。重新设计您的界面以创建一组控件,然后禁用整个组肯定是设计 UI 的更好方法。【参考方案4】:

当您嵌套了许多面板或 tableLayoutPanel 时,情况会变得很棘手。尝试禁用面板中的所有控件禁用父面板然后启用子控件根本不会启用该控件,因为未启用父级(或父级的父级)。为了保持启用所需的子控件,我将表单布局视为一棵树,表单本身作为根,任何容器或面板作为分支,子控件(按钮、文本框、标签等)作为叶节点。因此,主要目标是禁用与所需控件同一级别内的所有节点,将控件树一直向上爬到表单级别,建立启用控件的路径,以便子控件可以工作:

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
            
            
        
    

【讨论】:

以上是关于如何禁用表单上除按钮之外的所有控件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 LibreOffice Base 5.0.2.2 中创建一个按钮以禁用表单中的控件

如何从包含任何容器中的控件的表单中获取所有控件?

根据文本控件值标记和启用/禁用连续表单上的按钮

禁用控件后在 Access VBA 中显示禁用的控件

加载时禁用访问表单控件

Access 2007 中的选项卡控件之外的选项卡