0

I am trying to set the background color of a custom button. I build that button from HTML by overriding the Render method. I then expose certain attributes through customer overridden attribute methods with Get and set capabilities. This allows my to change parts of my custom button after compiling.

I want to change the color of the buttons div or table (i dont care which). How can i do this?

The button has a table - how can i programmatically grab this table given i know its name ;buttonTable.FindControl not working, i get 'not set to an instance of an object' error.

    Panel buttonPnl = new Panel(); //Declare and Init here in case you need it for changing background color at code compile and not run time
    System.Web.UI.WebControls.Image logoImg;
    System.Web.UI.WebControls.Image errorImg;
    TextBox mainTextTb;
    Label subTextLbl;

    protected override void CreateChildControls()
    {
        Controls.Clear();

        //init controls
        //buttonPnl.Width = Unit.Pixel(200);
        //buttonPnl.Height = Unit.Pixel(150);
        buttonPnl.ID = "buttonPnl";

        logoImg = new System.Web.UI.WebControls.Image();
        logoImg.ID = "logoImg";
        logoImg.Width = Unit.Pixel(75);
        logoImg.Height = Unit.Pixel(75);

        errorImg = new System.Web.UI.WebControls.Image();
        errorImg.ID = "errorImg";
        errorImg.Width = Unit.Pixel(50);
        errorImg.Height = Unit.Pixel(50);

        mainTextTb = new TextBox();
        mainTextTb.ID = "mainTextTb";
        mainTextTb.Text = "changed";
        mainTextTb.Font.Size = 20;
        mainTextTb.Width = Unit.Pixel(180);


        subTextLbl = new Label();
        subTextLbl.ID = "subTextLbl";
        subTextLbl.Text = "sub text";
        subTextLbl.Font.Size = 12;

        //add controls to parent control
        this.Controls.Add(logoImg);
        this.Controls.Add(errorImg);
        this.Controls.Add(mainTextTb);
        this.Controls.Add(subTextLbl);
        this.Controls.Add(buttonPnl);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        //render controls
        buttonPnl.RenderControl(writer);
        AddAttributesToRender(writer);
        writer.RenderBeginTag(HtmlTextWriterTag.Div); //table start tag
        writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "5");
        writer.AddAttribute(HtmlTextWriterAttribute.Width, "200");
        writer.AddAttribute(HtmlTextWriterAttribute.Id, "buttonTable");
        writer.RenderBeginTag(HtmlTextWriterTag.Table); //table start tag
        writer.RenderBeginTag(HtmlTextWriterTag.Tr); //row start tag
        writer.RenderBeginTag(HtmlTextWriterTag.Td); // cell start tag
        logoImg.RenderControl(writer); //add logo image
        writer.RenderEndTag(); //cell end tag
        writer.RenderBeginTag(HtmlTextWriterTag.Td); //cell start tag
        errorImg.RenderControl(writer); //add error image
        writer.RenderEndTag(); //cell end tag
        writer.RenderEndTag(); //row end tag
        writer.RenderBeginTag(HtmlTextWriterTag.Tr); //row start tag
        writer.AddAttribute(HtmlTextWriterAttribute.Width, "100%"); //make sure row width is 100% of parent
        writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2"); //make sure row spans 2 cells
        writer.RenderBeginTag(HtmlTextWriterTag.Td); //cell start tag
        mainTextTb.RenderControl(writer); //add main text box
        writer.RenderEndTag(); //cell end tag
        writer.RenderEndTag(); //row end tag
        writer.AddAttribute(HtmlTextWriterAttribute.Align, "right"); //make sure row width is 100% of parent
        writer.RenderBeginTag(HtmlTextWriterTag.Tr); //row start tag
        writer.AddAttribute(HtmlTextWriterAttribute.Width, "100%"); //make sure row width is 100% of parent
        writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2"); //make sure row spans 2 cells
        writer.RenderBeginTag(HtmlTextWriterTag.Td); //cell start tag
        subTextLbl.RenderControl(writer); //add sub label
        writer.RenderEndTag();//cell end tag
        writer.RenderEndTag(); //row end tag
        writer.RenderEndTag(); //table end tag
        writer.RenderEndTag(); //div end tag
    }

    [Category("Appearance")]
    [Description("Gets or sets the panel colour")]
    public Color TimbusButtonColour
    {                

        get
        {
            EnsureChildControls();
            Table buttonTbl = (Table)this.FindControl("buttonTable");
            //return buttonPnl.BackColor;
            return buttonTbl.BackColor;
        }

        set
        {
            if (value != null)
            {
                Table buttonTbl = (Table)this.FindControl("buttonTable");
                //buttonPnl.BackColor = Color.FromArgb(value.R, value.G, value.B);
                buttonTbl.BackColor = Color.FromArgb(value.R, value.G, value.B);
            }
        }
    }

resulting HTML from pages source code

</div><div id="Button1">
    <table cellpadding="5" width="200" id="buttonTable">
        <tr>
            <td><img id="Button1_logoImg" src="" style="height:75px;width:75px;" /></td><td><img id="Button1_errorImg" src="" style="height:50px;width:50px;" /></td>
        </tr><tr>
            <td width="100%" colspan="2"><input name="Button1$mainTextTb" type="text" value="changed" id="Button1_mainTextTb" style="font-size:20pt;width:180px;" /></td>
        </tr><tr align="right">
            <td width="100%" colspan="2"><span id="Button1_subTextLbl" style="font-size:12pt;">sub text</span></td>
        </tr>
    </table>
</div>
Fearghal
  • 10,569
  • 17
  • 55
  • 97
  • Can't you set the background of buttonPnl and add all other controls to that panel? That will become a div when rendered, with the background color set. – Patrick Nov 13 '14 at 14:28
  • You should not expect to find something that you have not created. Rendered `div` with `id="buttonTable"` does not magically become `Table` control in control tree. – Igor Nov 13 '14 at 14:41
  • @patrick can you elaborate -do you mean add the controls to the panel like buttonPanel.Controls.Add(controlsXXX); and then this.add(buttonPanel); I cant do this as I need to position the controls within the panel so i do this via the Render method using a div instead of panel Or do you mean add panel into html like buttonPnl.RenderControl(writer);? the prob with this is how do i close the panel tag? – Fearghal Nov 13 '14 at 14:44
  • @Igor the table is called buttonTable, no magic involved. I checked it in the resulting pages sourceCode. – Fearghal Nov 13 '14 at 14:44
  • Of course, there is no magic involved. However, I do not see `new Table()` in your code. How do you think the instance of `Table` will come to life? – Igor Nov 13 '14 at 14:47
  • @Igor. Cheers for response. The Render method has a line that sets the table attribute with it dynamically created in html at render. writer.AddAttribute(HtmlTextWriterAttribute.Id, "buttonTable");.the line you refer to is an attempt to grab that table control by its name. It doesnt appear to work . The dififculty i have is im compiling this c# and importing it into a asp .net project and dropping it from the tool box - its here i see the error in the attribute i created – Fearghal Nov 13 '14 at 14:49
  • @Fearghal - I am not getting through to you. You are trying to obtain a reference to an instance of `Table` control. There is no `Table` control. Rendering something with `id="buttonTable"` only outputs html, no control instances are created. – Igor Nov 13 '14 at 14:54
  • Oh ok. I thought that because there was a html Table that i could get control of that. Any ideas on an alt fix? – Fearghal Nov 13 '14 at 15:04
  • If I recall correctly you should either use Render **or** CreateChildControls. If you use CreateChildControls correctly you don't need to edit the Render method, and you can interact with all controls using events and properties. – Patrick Nov 13 '14 at 15:19
  • @Patrick - i do it in render so i can position my components better – Fearghal Nov 13 '14 at 15:50
  • 1
    Well don't.. use the properties of the components, such as margin, padding, width and height and see what happens. You will get a cleaner control class, because you only change the appearance in one place. – Patrick Nov 13 '14 at 15:54

2 Answers2

1

You should use a function similar to this:

public static Control FindControlRecursive(Control ctl, string id) {
    if (!ctl.HasControls())
        return null;
    Control res = null;
    foreach(Control c in ctl.Controls) {
        if (c.ID == id) {
            res = c;
            break;
        } else {
            res = FindControlRecursive(c, id);
            if (res != null)
                break;
        }
    }
    return res;
}

in this way:

Table buttonTbl = (Table)FindControlRecursive(this.Page, "buttonTable");

And you will find your control for sure.

SmartDev
  • 2,802
  • 1
  • 17
  • 22
  • Recursive search has nothing to do with OP's problem. He is looking for a control that simply does not exist. – Igor Nov 13 '14 at 14:55
  • @SmartDev thats a good idea, i still get the same error in the exposed attribute TimbusButtonColour - 'ObjectReference not set to an instance of an object' I think this could be that the table is declared inside that TimbusButtonColour but i moved it to top and still same issue. Help! – Fearghal Nov 13 '14 at 14:58
  • @Igor - how can i get control of the table html tag? – Fearghal Nov 13 '14 at 15:15
  • @Fearghal - you need to understand "cause and effect" in ASP.NET - there will be no control just because you rendered something to html. Add a member of `Table` type to your class definition and create this `Table` as well as `TableRow`s and `TableCell`s in `CreateChildControls`. – Igor Nov 13 '14 at 15:21
  • can you elaborate? then what do i do? – Fearghal Nov 13 '14 at 15:26
0

Thx Igor and Patrick et al, great feedback put me back on the right path, ie creating controls and not going straight to dynamically writting html. seems obv but there you go.

    protected override void CreateChildControls()
    {
        Controls.Clear();

        //init controls
        buttonTbl = new Table();
        buttonPnl.ID = "buttonPnl";

        logoImg = new System.Web.UI.WebControls.Image();
        logoImg.ID = "logoImg";
        logoImg.Width = Unit.Percentage(100);//100% of cell width
        logoImg.Height = Unit.Percentage(100);//100% of cell width

        errorImg = new System.Web.UI.WebControls.Image();
        errorImg.ID = "errorImg";
        errorImg.Width = Unit.Percentage(50);//50% of cell width
        errorImg.Height = Unit.Percentage(50);//50% of cell height

        mainTextTb = new TextBox();
        mainTextTb.ID = "mainTextTb";
        mainTextTb.Text = "changed";
        mainTextTb.Font.Size = 20;
        mainTextTb.Width = Unit.Percentage(100);

        subTextLbl = new Label();
        subTextLbl.ID = "subTextLbl";
        subTextLbl.Text = "sub text";
        subTextLbl.Font.Size = 12;

        //format table
        buttonTbl.Width = 200;
        buttonTbl.Height = 150;
        buttonTbl.CellPadding = (int)Unit.Percentage(5).Value;
        //add the 3 rows
        buttonTbl.Rows.Add(imgRow);
        buttonTbl.Rows.Add(mainTextRow);
        buttonTbl.Rows.Add(subTextRow);
        //add the cells
        imgRow.Cells.Add(logoImgCell);
        imgRow.Cells.Add(errorImgCell);
        mainTextRow.Cells.Add(mainTextCell);
        subTextRow.Cells.Add(subTextCell);
        //add controls to their cells
        logoImgCell.Controls.Add(logoImg);
        errorImgCell.Controls.Add(errorImg);
        mainTextCell.Controls.Add(mainTextTb);
        subTextCell.Controls.Add(subTextLbl);
        //position cells
        logoImgCell.HorizontalAlign = HorizontalAlign.Right;
        logoImgCell.VerticalAlign = VerticalAlign.Top;
        errorImgCell.HorizontalAlign = HorizontalAlign.Right;
        errorImgCell.VerticalAlign = VerticalAlign.Top;
        mainTextCell.ColumnSpan = 2;
        subTextCell.ColumnSpan = 2;
        subTextCell.HorizontalAlign = HorizontalAlign.Right;

        this.Controls.Add(buttonTbl);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        //render controls
        buttonTbl.RenderControl(writer);
    }

    [Category("Appearance")]
    [Description("Gets or sets the panel colour")]
    public Color TimbusButtonColour
    {                
        get
        {
            EnsureChildControls();
            return buttonTbl.BackColor;
        }

        set
        {
            if (value != null)
            {
                buttonTbl.BackColor = Color.FromArgb(value.R, value.G, value.B);
            }
        }
    }
Fearghal
  • 10,569
  • 17
  • 55
  • 97