使用FindControl()查找动态控件时返回Null的技术问题求助
Hey there! I’ve run into this exact issue with dynamic ASP.NET controls before—let’s walk through why your FindControl() is returning null and how to fix it.
The Core Problem: ASP.NET Page Lifecycle & Dynamic Controls
Here’s the root cause: When you create dynamic controls (like your TextBoxes and Checkboxes) inside an event handler (e.g., ddlenqChaged or your button click), those controls only exist for that single page request. On the next postback (like when you click the save button), ASP.NET doesn’t automatically recreate those controls. Since they’re not in the page’s control tree, FindControl() can’t locate them.
Dynamic controls need to be recreated on every postback, and this has to happen early in the page lifecycle (preferably in Page_Init or the start of Page_Load)—before event handlers fire. This lets ASP.NET bind view state and recognize the controls when events trigger.
Step-by-Step Solution
Let’s break down the fixes with code examples tailored to your scenario:
1. Store State to Track What Controls Need to Be Recreated
First, we’ll use ViewState to save key information about the dynamic controls (like the selected dropdown value and product IDs) so we can recreate them on every postback.
2. Recreate Dynamic Controls Early in the Lifecycle
Add code to Page_Init to rebuild your dynamic controls every time the page loads, using the state stored in ViewState.
protected void Page_Init(object sender, EventArgs e) { // Check if we have a selected enquiry (from dropdown) if (ViewState["SelectedEnquiry"] != null) { // Recreate the two TextBoxes first var txtEnqId1 = new TextBox { ID = "txtEnqId1" }; // Restore the text value from ViewState if available txtEnqId1.Text = ViewState["txtEnqId1_Value"]?.ToString() ?? string.Empty; pnlDynamicContainer.Controls.Add(txtEnqId1); var txtEnqId2 = new TextBox { ID = "txtEnqId2" }; txtEnqId2.Text = ViewState["txtEnqId2_Value"]?.ToString() ?? string.Empty; pnlDynamicContainer.Controls.Add(txtEnqId2); // If we've already loaded product checkboxes, recreate those too if (ViewState["ProductIds"] != null) { var productIds = ViewState["ProductIds"] as List<int>; foreach (int id in productIds) { var chkProduct = new CheckBox { ID = $"chkProduct_{id}", // Critical: Use a consistent, unique ID Text = $"Product {id}" // Replace with your product name logic }; // Restore checked state from ViewState chkProduct.Checked = ViewState[$"chkProduct_{id}_Checked"] != null ? (bool)ViewState[$"chkProduct_{id}_Checked"] : false; pnlDynamicContainer.Controls.Add(chkProduct); } } } }
3. Update Your Dropdown SelectedIndexChanged Handler
Modify your dropdown event to save state and create the initial TextBoxes (which will then be recreated on postback via Page_Init):
protected void ddlenqChaged(object sender, EventArgs e) { // Clear existing controls in the container pnlDynamicContainer.Controls.Clear(); // Create and add the two TextBoxes var txtEnqId1 = new TextBox { ID = "txtEnqId1" }; var txtEnqId2 = new TextBox { ID = "txtEnqId2" }; pnlDynamicContainer.Controls.Add(txtEnqId1); pnlDynamicContainer.Controls.Add(txtEnqId2); // Save the selected dropdown value to ViewState for postback recreation ViewState["SelectedEnquiry"] = ddlEnquiry.SelectedValue; // Reset product state since we're starting fresh ViewState["ProductIds"] = null; }
4. Update Your Button Click Handler to Load Products
When the button is clicked, get the TextBox values, load your products, save their IDs to ViewState, and create the checkboxes (which will be recreated on subsequent postbacks):
protected void btnLoadProducts_Click(object sender, EventArgs e) { // Find the TextBoxes (they're already recreated in Page_Init, so this works!) var txtEnqId1 = pnlDynamicContainer.FindControl("txtEnqId1") as TextBox; var txtEnqId2 = pnlDynamicContainer.FindControl("txtEnqId2") as TextBox; if (txtEnqId1 == null || txtEnqId2 == null) return; // Get your enquiry numbers from the TextBoxes string enqId1 = txtEnqId1.Text; string enqId2 = txtEnqId2.Text; // Load your product list (replace with your actual business logic) var products = GetProductsByEnquiryIds(enqId1, enqId2); var productIds = products.Select(p => p.Id).ToList(); // Save TextBox values and product IDs to ViewState ViewState["txtEnqId1_Value"] = enqId1; ViewState["txtEnqId2_Value"] = enqId2; ViewState["ProductIds"] = productIds; // Clear the container and recreate all controls (TextBoxes + Checkboxes) pnlDynamicContainer.Controls.Clear(); // Re-add TextBoxes with saved values pnlDynamicContainer.Controls.Add(new TextBox { ID = "txtEnqId1", Text = enqId1 }); pnlDynamicContainer.Controls.Add(new TextBox { ID = "txtEnqId2", Text = enqId2 }); // Add Checkboxes for each product foreach (var product in products) { var chkProduct = new CheckBox { ID = $"chkProduct_{product.Id}", // Consistent ID is key Text = product.Name }; pnlDynamicContainer.Controls.Add(chkProduct); } }
5. Fix the Save Handler to Find Checkboxes
Now when you click save, the checkboxes are already recreated in Page_Init, so FindControl() will find them:
protected void btnSaveProducts_Click(object sender, EventArgs e) { var selectedProductIds = new List<int>(); var productIds = ViewState["ProductIds"] as List<int>; if (productIds == null) return; foreach (int id in productIds) { // Look for the checkbox in the container (not directly on the page!) var chkProduct = pnlDynamicContainer.FindControl($"chkProduct_{id}") as CheckBox; if (chkProduct != null && chkProduct.Checked) { selectedProductIds.Add(id); } } // Run your save logic here with selectedProductIds SaveSelectedProducts(selectedProductIds); }
Key Takeaways
- Recreate on every postback: Dynamic controls must be rebuilt early in the page lifecycle (
Page_Initis best) to be part of the control tree. - Consistent IDs: Use the exact same ID for each dynamic control every time you recreate it—this is how ASP.NET tracks view state and recognizes the control.
- Use a container: Always add dynamic controls to a container (like a
Panel) instead of directly to the page. This makesFindControl()more reliable and avoids issues with control tree hierarchy. - Save state: Use
ViewStateto store any data needed to recreate controls (like selected values, product IDs, or input text).
内容的提问来源于stack exchange,提问作者Hisanth

