Meli
Meli

Reputation: 13

Controls property and FindControl function C#

I'm coding a calendar that displays some events. Each day has a button for morning, afternoon and night events, when there are events to show the button is enabled and its color is changed. I am displaying these buttons in an html table and when someone changes the month being displayed the program has to "cleanup" the buttons by disabling all of them and setting their colors to white again. Thing is I was able to enable them by using the FindControl method on the table containing the buttons this way:

string butControl = /* id of the button */
Button block = mainTable.FindControl(butControl) as Button;
block.BackColor = Color.Gray;
block.Enabled = true;

And it works fine. In my cleanup method I don't want to call all the names of the buttons because there are 105, instead I used this method:

    private void CleanUp()
    {
        foreach (Control c in mainTable.Controls)
        {
            Button bot = c as Button;
            if (bot != null)
            {
                bot.BackColor = Color.White;
                bot.Enabled = false;
            }
        }
    }

But this does not change the color or enabled property of any of the buttons. My question is: Are not the controls in the Controls property of the table the same that can be found via the FindControl method? Or am I doing something wrong when retrieving the controls?

Upvotes: 1

Views: 1787

Answers (2)

atlaste
atlaste

Reputation: 31146

Isn't the problem that in you're iterating a list of controls rather than the hierarchy? FindControl uses the hierarchy. You can loop the controls as follows:

public IEnumerable<T> EnumerateRecursive<T>(Control root) where T : Control
{
    Stack<Control> st = new Stack<Control>();
    st.Push(root);

    while (st.Count > 0)
    {
        var control = st.Pop();
        if (control is T)
        {
            yield return (T)control;
        }

        foreach (Control child in control.Controls)
        {
            st.Push(child);
        }
    }
}

public void Cleanup() 
{
    foreach (Button bot in EnumerateRecursive<Button>(this.mainTable))
    {
        bot.BackColor = Color.White;
        bot.Enabled = false;
    }
}

You can implement it using recursion as well, but I usually prefer a stack because it is much faster.

Upvotes: 2

machine
machine

Reputation: 1400

I assume that you're using an ASP table, as that would certainly not work. You could get around it in other ways, but if it doesn't matter to you to use some HTML, I would suggest that you restructure it to look like this:

<form id="form1" runat="server">
    <asp:Panel ID="mainTable" runat="server">
        <table>
            <tr>
                <td>
                    <asp:Button ID="Button1" runat="server" Text="Button" />
                </td>
            </tr>
        </table>
    </asp:Panel>
</form>

Note the use of only html controls inside the asp:Panel except for the actual buttons. Using ASP, you would have to recursively look for children.

EDIT: Speaking of recursively looking for children, Stefan made that exact suggestion and provided code before I finished writing, and I would definitely recommend his method; he's evidently much less lazy than me.

==================================

Stefan's approach has a slight error in that you can't explicitly typecast without knowing a type, and you can't know a type if you use generics, as he has. Here is a lazy adaptation for use purely with buttons, as you are using it for.

Do not give this "answer" status. It is a corruption of someone else's work.

public IEnumerable<Button> EnumerateRecursive(Control root)
{
    // Hook everything in Page.Controls
    Stack<Control> st = new Stack<Control>();
    st.Push(root);

    while (st.Count > 0)
    {
        var control = st.Pop();
        if (control is Button)
        {
            yield return (Button)control;
        }

        foreach (Control child in control.Controls)
        {
            st.Push(child);
        }
    }
}

public void Cleanup()
{
    foreach (Button bot in EnumerateRecursive(this.mainTable))
    {
        bot.BackColor = Color.White;
        bot.Enabled = false;
    }
}

Upvotes: 0

Related Questions