yrazlik
yrazlik

Reputation: 10777

C# button click event does not fire

I have seen a couple of similar questions but none of the solutions worked for me. I have a table and i dinamically add a couple of buttons to it like the following, and i want a single common listener for all buttons:

Button b; //This is defined as a variable in class, not in a function 
...
...

void someFunction( . . . )
{
     foreach (DataRow row in table.Rows)
     {
          try
          {
               string starthour = row["starthour"].ToString(), endhour = row["endhour"].ToString(), day = row["day"].ToString(), building = row["building"].ToString(), room = row["room"].ToString();

                int start = Convert.ToInt32(starthour.Substring(0, starthour.Length - 2));
                int end = Convert.ToInt32(endhour.Substring(0, endhour.Length - 2));

                int startindex = getHourIndex(start);
                int endindex = getHourIndex(end);

               int dayindex = getDayIndex(day);

               for (int i = startindex; i < endindex; i++)
               {
                   b = new Button();
                   b.Text = subj + numb + " " + section;



                   Color clr = getCourseColor(subj + numb + section, courses);
                   b.BackColor = clr;
                   b.Enabled = true;

                   b.Click += new EventHandler(button_Click);
                   table_filter_instructor_schedule.Rows[i].Cells[dayindex].Controls.Add(b);

               }
         }
         catch (Exception)
         {

         }
    }
}

And here is the event handler:

protected void button_Click(object sender, EventArgs e)
{

        Response.Redirect("Default.aspx");

}

but the problem is, ebent handler function is never called. Can anyone help me with this*

Thanks

EDIT: Here is how the page looks, and i want to add listener for those buttons:

enter image description here

Upvotes: 0

Views: 806

Answers (2)

Markus
Markus

Reputation: 22456

If you want dynamic controls to work and also raise events, you need to recreate them early in the page lifecycle (Page_Init, Page_Load at the latest). It is important that you assign the same IDs when you recreate the controls and also wire up the event handlers.

Using dynamically created controls usually adds a lot of complexity and you should check whether there is no other way that is simpler. In your function, your buttons are created based on a data table. So it might be a good approach to use a repeater instead of the dynamically created buttons. This allows to wire up events statically.

For a detailed sample on how to create controls dynamically, see this link. However, it also suggests to favor a static approach if possible:

Existing controls can often provide the functionality you get from creating controls dynamically. For example, controls such as the Repeater, DataList, and RadioButtonList controls can dynamically create rows or other control elements when the page runs.

How to avoid adding controls dynamically in your case

In your specific case (based on your image), I'd propose the following static approach:

  1. Add a Repeater to your page that creates the table header in the header template, the rows in the ItemTemplate and the table footer in the FooterTemplate. Add a button for each day in the ItemTemplate. Wire an event to the buttons.
  2. Create a data class that represents one line in the repeater, e.g. time and the data for each day.
  3. When you retrieve the data, convert it to a list of the data class and bind the repeater to it.
  4. Handle the OnItemDataBound event of the repeater to adjust the visibility of the buttons and set the text.

The following sample shows the main parts (I've added only columns for three days):

Repeater

This Repeater creates a very basic HTML table. Please note the buttons in the table rows and the static registration of an event handler.

<asp:Repeater ID="rptTimeTable" runat="server" OnItemDataBound="rptTimeTable_ItemDataBound">
    <HeaderTemplate>
        <table>
            <thead>
                <tr>
                    <td>Time</td>
                    <td>Mon</td>
                    <td>Tue</td>
                    <td>Wed</td>
                </tr>
            </thead>
            <tbody>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td><%# Eval("Time", "{0:t}") %></td>
            <td>
                <asp:Button ID="btnMon" runat="server" OnClick="btn_ClickHandler" />
            </td>
            <td>
                <asp:Button ID="btnTue" runat="server" OnClick="btn_ClickHandler" />
            </td>
            <td>
                <asp:Button ID="btnWed" runat="server" OnClick="btn_ClickHandler" />
            </td>
        </tr>
    </ItemTemplate>
    <FooterTemplate>
            </tbody>
        </table>
    </FooterTemplate>
</asp:Repeater>

Data Class

The data class stores a text for each button that I put on the button later on.

public class RepeaterData
{
    public DateTime Time { get; set; }
    public string MonText { get; set; }
    public string TueText { get; set; }
    public string WedText { get; set; }
}

Data binding

I've placed this in Page_Load (only if it is not a PostBack), but you can run this whenever you like.

var data = new List<RepeaterData>();
data.Add(new RepeaterData() { Time = DateTime.Today.AddHours(9), MonText = "123", TueText = null, WedText = null });
data.Add(new RepeaterData() { Time = DateTime.Today.AddHours(10), MonText = null, TueText = "456", WedText = "789" });
data.Add(new RepeaterData() { Time = DateTime.Today.AddHours(11), MonText = null, TueText = null, WedText = null });
data.Add(new RepeaterData() { Time = DateTime.Today.AddHours(12), MonText = "123", TueText = null, WedText = null });
rptTimeTable.DataSource = data;
rptTimeTable.DataBind();

OnItemDataBound handler

protected void rptTimeTable_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        var data = (RepeaterData)e.Item.DataItem;
        SetButtonText(e.Item, "btnMon", data.MonText);
        SetButtonText(e.Item, "btnTue", data.TueText);
        SetButtonText(e.Item, "btnWed", data.WedText);
    }
}

private void SetButtonText(RepeaterItem repeaterItem, string btnId, string btnText)
{
    var btn = repeaterItem.FindControl(btnId) as Button;
    if (btn != null)
    {
        if (!string.IsNullOrEmpty(btnText))
            btn.Text = btnText;
        else
            btn.Visible = false;
    }
}

Button click handler

protected void btn_ClickHandler(object sender, EventArgs e)
{
    // Do whatever you like
}

Upvotes: 1

Peter
Peter

Reputation: 27944

The problem is that you generate dynamic buttons on your asp page, the ids generated have to be the same over the lifetime of the page. If not the button can not be found at serverside on a postback. The cause can be that you build your table multiple times in the request handling.

Upvotes: 0

Related Questions