【问题标题】:All buttons state change in C# [duplicate]C#中的所有按钮状态更改[重复]
【发布时间】:2020-07-23 17:27:36
【问题描述】:

我要做的是在按钮处于活动状态后更改按钮的背景颜色。到目前为止,我通过这种方式实现了它:

 private void button3_Click(object sender, EventArgs e) // METEO BUTTON
        {
            DefaultButtons();
            button3.BackColor = Color.LimeGreen;
// REST OF THE CODE HOES HERE
        }

而 DefaultButtons 函数是这样的:

public void DefaultButtons()
        {
            List<Button> buttonsToDefualt = new List<Button>()
        {
                // MAIN MENU
            button1,
            button2,
           [...]
            buttonX
        };
            foreach (var item in buttonsToDefualt)
            {
                item.BackColor = Color.Green;
            }
        }

现在交换按钮的工作方式如下:将整个列表更改为默认颜色,然后激活按钮将颜色更改为 LimeGreen。没关系,但是: 1) 我必须启动 DefaultButtons();对于每个按钮单击 2)我必须手动将所有按钮添加到列表中,现在我有120多个按钮(是的,正在构建自定义界面......),并且继续手动添加很累。

我试过了:

void DefaultButtonsNew()
        {
            foreach (Button b in this.Controls)
            {
                if (b != null)
                {
                    b.BackColor = Color.Green;
                }
            }
        } 

但是我有一个异常:System.InvalidCastException: 'Can't throw object 'System.Windows.Forms.SplitContainer' on type 'System.Windows.Forms.Button'。'

【问题讨论】:

  • foreach (Button b in this.Controls.OfType&lt;Button&gt;()) { b.BackColor = Color.Green; }
  • 或混合:foreach (Control c in this.Controls) { if (c is Button b){ b.BackColor = Color.Green; } if (c is TextBox t) { t.BackColor = Color.Red; } }
  • 请注意,您没有指定这些控件是窗体的子控件还是代替另一个容器(Panel、TableLayoutPanel 等),或者两种情况都是可能的。如果是这种情况,当然this.Controls 不会找到它们。目前尚不清楚您为什么不使用List&lt;Button&gt;,也不清楚您是否在某个时候从该列表中删除了控件(因为场景发生了变化 - 有点,但足够了)。
  • 您是要更改表单上的 所有 按钮,还是仅更改特定容器中的按钮?您如何确定需要更改背景颜色的按钮?
  • 我猜你应该使用 Leave 或 LostFocus 事件。

标签: c#


【解决方案1】:

如果您正在寻找一种方法来重置表单上的所有按钮,并且一些按钮位于其他容器中,那么我们需要递归循环每个控件的Controls 收藏找到所有按钮。

一种简单的方法是编写一个方法,该方法接收一个容器(如表单),遍历其Controls 集合,更改任何Button 控件的BackColor,并为其他控件类型:

private void ResetButtons(Control container)
{
    // Loop through each control in this container
    foreach (Control control in container.Controls)
    {
        var button = control as Button;

        // If the control is a button, change it's backcolor
        if (button != null) button.BackColor = Color.Green;
        // Otherwise check it's controls collection (recursive call)
        else ResetButtons(control);
    }
}

接下来,听起来您正在寻找一种方法来避免写出对该方法的调用,并在每个按钮单击事件中更改当前按钮的BackColor。

解决此问题的一种简单方法是简单地添加此方法,并将BackColor 更改为每个 按钮在代码中单击。我们可以使用类似的模式编写一个方法来执行此操作 - 循环遍历每个容器中的每个控件,如果它是一个按钮,则为其单击事件添加一个方法:

private void HookupButtonClickEvent(Control container)
{
    // Loop through each control in this container
    foreach (Control control in container.Controls)
    {
        var button = control as Button;

        // If the control is a button, add a method to it's click event
        if (button != null)
        {
            button.Click += (s, e) =>
            {
                ResetButtons(container);
                button.BackColor = Color.LimeGreen; // Change this button's color
            };
        }
        // Otherwise check it's controls collection (recursive call)
        else HookupButtonClickEvent(control);
    }
}

现在,我们所要做的就是在表单的构造函数中调用ResetButtons 和HookupButtonClickEvent,每个 按钮都将以相同的背景颜色开始,并在其中调用我们的重置方法点击事件:

public Form1()
{
    InitializeComponent();

    HookupButtonClickEvent(this);
    ResetButtons(this);
}

请注意,这不会阻止您向按钮添加额外的点击事件。它只是提供了一种将通用功能连接到所有按钮的方法,而无需编写一堆重复的代码。

您仍然可以双击表单上的控件来添加其他 Click 事件处理程序:

private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("Button one clicked - doing something unique here");
}

private void button2_Click(object sender, EventArgs e)
{
    MessageBox.Show("Button two clicked - doing something else here");
}

【讨论】:

  • 几乎完美,但如何添加例外(110 个按钮中的 2 个不可更改)?另外,在您按下特定按钮(菜单类型 -> 子菜单方案)后,会出现一堆新按钮,而您的代码虽然运行良好,但会改变一切:prnt.sc/rx3eqa 这就是它应该如何工作:prnt.sc/rx3fk0 应该一开始就提到了,对此感到抱歉。
  • 要处理不同的菜单,你可以传入不同的容器名称吗?所以不是ResetButtons(this);,而是ResetButtons(mainMenuContainer);。对于额外的一两个按钮,一种想法是在其Tag 属性中添加一些内容,例如"IgnoreMe",然后在代码中if (button != null) 将更改为if (button != null &amp;&amp; button.Tag != "IgnoreMe")
  • 我更新了HookupButtonClickEvent 代码,使它只为传入的容器中的控件调用ResetButtons。
【解决方案2】:

Controls 集合上的迭代器返回所有控件,并在执行失败时尝试将其转换为 Button。

像这样改变你的方法:

    void DefaultButtonsNew()
    {
        foreach (Control b in this.Controls)
        {
            if (b is Button)
            {
                b.BackColor = Color.Green;
            }
        }
    }

【讨论】:

  • 使用Controls.OfType&lt;Button&gt;() 作为循环集合怎么样?
  • 不幸的是,即使脚本没有崩溃,它也没有做它应该做的事情(任何带有 Color.LimeGreen 的先前按钮都不会恢复prnt.sc/rx2hi3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 1970-01-01
相关资源
最近更新 更多