Calling a server side method from a dynamically generated button inside an update panel

Viewed 171

Lets preface this with the fact that I am learning ASP.NET C# and this is my first "real" project so there is a good chance I am missing something obvious, I apologize in advance.

I am working on a web page that displays three columns. The first is "Categories", a user should be able to select a category then have a list of items to choose from appear in the second column "Items". When they click an item the third column should show details about said item. For the most part this is a classic Master/Detail scenario except we take it a step further and do Master/Detail/Detail.

To achieve this I am generating dynamic buttons on Page_Load() in the "Categories" column. In addition I have added a debug line when the page loads, this is important later.

 protected void Page_Load(object sender, EventArgs e)
        {
            //DB query to get categories omitted

            for (int i = 0; i < categories.Rows.Count; i++)
            {
                Button btn = new Button();
                btn.Click += new System.EventHandler(CategorySelected_Click);
                btn.Attributes["runat"] = "server";
                btn.ID = "CatSelBtn" + i;
                btn.Attributes["data-categoryid"] = qry.GetCategories().Rows[i]["id"].ToString();
                //And some other non-relevant attributes
                CategoriesPane.Controls.Add(btn);
            }
            System.Diagnostics.Debug.WriteLine("Page Loaded");
       }

As you may have noticed these buttons have a Click event handler that calls the method CategorySelected_Click(). These buttons all generate successfully and clicking on them results in that method being successfully called. This method is set up in a similar fashion, it grabs a list of items then generates buttons for the items, of course this needs to be done asynchronously so it doesn't reset the user's category selection, so this time it is all contained with an update panel.

C#

protected void CategorySelected_Click(object sender, EventArgs e)
            {
                //DB query to get items omitted

                Button btn = (sender as Button);
                string categoryid = btn.Attributes["data-categoryid"].ToString();

                for (int i = 0; i < items.Rows.Count; i++)
                {
                    if (items.Rows[i]["Category"].ToString() == categoryid)
                    {
                        Button ibtn = new Button();
                        ibtn.Click += new System.EventHandler(this.ItemSelected_Click);
                        ibtn.Attributes["runat"] = "server";
                        ibtn.ID = "ItmSelBtn" + i;
                        ibtn.Attributes["data-itemid"] = qry.GetItems().Rows[i]["id"].ToString();
                        //And again some none relevant attributes here
                        ItemsParent.Controls.Add(ibtn);
                    }
                }

                ItemsPanel.Update();
            }

ASP

 <div class="col-md-2 items-pane">
                <asp:UpdatePanel ID="ItemsPanel" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False">
                    <ContentTemplate>
                        <div id="ItemsParent" runat="server">

                        </div>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>
            <div class="col-md-8 view-pane">
                <asp:UpdatePanel ID="ItemDetailsPanel" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False">
                    <ContentTemplate>
                        <div id="ItemDetailsParent" runat="server">

                        </div>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>

Again this generates a list of buttons for each item matching the correct category. No issue there, but this time I need the clicked button to call the third and final method which will display the details for the item. This is where things stop working. I assumed that because I was able to generate buttons successfully on Page_Load() that it would work the same inside an update panel. Right now the third method just contains a debug line to check if its firing at all.

protected void ItemSelected_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Item has been selected");
            ItemDetailsPanel.Update();
        }

In my output console in visual studio when I click on an Item Button control it writes Page Loaded indicating a successful postback but I am not seeing Item has been selected indicating that the third method is firing. I also inserted a breakpoint there but it is not being reached.

I initially thought I needed to add an asyncpostback trigger for each button generated to my update panel but that did not seem to resolve that issue, and because I can now see that Page_Load() is getting triggered I am pretty sure that isn't the issue. This leads me to believe that the click event is somehow not being registered. So my question to you is this: How do I make a dynamically generated button inside an update panel call a server side method? Any help is greatly appreciated.

1 Answers

You need to attach the event handlers on every postback. It works for your categories-buttons, because the attaching is executed on every page load. Do this for all the other items also, e.g. put in your Page_Load something like this:

foreach (var ctrl in ItemsParent.Controls) 
{
  Button ibtn = ctrl as Button;
  if (ibtn != null) 
  {
    ibtn.Click += new System.EventHandler(this.ItemSelected_Click);
  }
}
Related