Saturday, June 27, 2015

ASP.Net C# Finding Controls in Nested Repeaters on Button Click Event

Here's a simple way to find controls in a nested repeater on a button click event.

Let's start with the ASPX page.
 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="Web.nested_repeaters._default" %>  
   
 <!DOCTYPE html>  
   
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head runat="server">  
   <!-- title -->  
   <title>Repeater Test</title>  
   
   <!-- jquery -->  
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

   <!-- bootstrap -->  
   <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />  
   <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>  
   
   <!-- custom style -->  
   <style>  
     body {  
       margin: 25px !important;  
     }  
   
     .form-group {  
       width: 800px;  
     }  
   </style>  
 </head>  
   
 <body>  
   <form id="form1" runat="server">  
     <asp:Repeater ID="lstCategories" runat="server">  
       <ItemTemplate>  
         <div class="col-sm-12">  
           <h2><%#Eval("Name")%></h2>   
               
           <asp:Repeater ID="lstTasks" DataSource='<%#Eval("Tasks")%>' runat="server">  
             <ItemTemplate>   
               <div class="form-group">   
                 <div class="col-sm-12">  
                   <div class="col-sm-2">  
                     <%#Eval("Name")%>  
                   </div>  
                   <div class="col-sm-10">  
                     <!-- hidden fields -->  
                     <asp:HiddenField ID="lblID" Value='<%#DataBinder.Eval(Container.DataItem, "ID")%>' runat="server" />  
                     <asp:HiddenField ID="lblValue" Value='<%#DataBinder.Eval(Container.DataItem, "Value")%>' runat="server" />  
   
                     <!-- textbox to show current value and to allow updates -->  
                     <asp:TextBox ID="txtValue" Text='<%#DataBinder.Eval(Container.DataItem, "Value")%>' MaxLength="100" CssClass="form-control" runat="server" />  
                   </div>  
                 </div>  
               </div>  
             </ItemTemplate>  
           </asp:Repeater>  
         </div>  
       </ItemTemplate>  
     </asp:Repeater>  
   
     <div class="col-sm-12" style="padding-top: 25px">  
       <asp:Button ID="btnSave" Text="Save Changes" CssClass="btn btn-primary" Style="margin-right: 25px" OnClick="btnSave_Click" ClientIDMode="Static" runat="server" />  
       <asp:Button ID="btnCancel" Text="Cancel" CssClass="btn btn-primary" OnClick="btnCancel_Click" ClientIDMode="Static" runat="server" />  
     </div>  
   
     <!-- debug -->  
     <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" style="padding-top: 25px">  
       <asp:PlaceHolder ID="pnlDebug" Visible="true" runat="server" />  
     </div>  
   </form>  
 </body>  
 </html>  

For this example I'm using lstCategories for the outer repeater and lstTasks for the nested repeater. The nested repeater (lstTasks) defines 3 controls:

lblID This is the hidden field for the ID to identify your record (e.g. primary key)
lblValue This is the hidden field representing the original value of the field
txtValue This is a textbox that defaults to the current value, but can be edited

Then there are 2 buttons.

btnSave Iterates the repeaters to access the controls
btnCancel Reloads the page

Then the code-behind looks like this:
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.Web.UI;  
 using System.Web.UI.WebControls;  
   
 namespace Web.nested_repeaters  
 {  
   public partial class _default : System.Web.UI.Page  
   {  
     protected void Page_Load(object sender, EventArgs e)  
     {  
       if (!Page.IsPostBack)  
       {  
         BindData();  
       }  
     }  
   
     private void BindData()  
     {  
       lstCategories.DataSource = GetData();  
       lstCategories.DataBind();  
     }  
   
     private List<Category> GetData()  
     {  
       // variables  
       List<Category> Categories = new List<Category>();  
   
       // category 1  
       Category Category1 = new Category() { Name = "General", Tasks = new List<Task>() };  
       Category1.Tasks.Add(new Task() { ID = 1, Name = "Name", Value = "John Wick" });  
       Category1.Tasks.Add(new Task() { ID = 2, Name = "Email", Value = "info@pavey.net" });  
       Category1.Tasks.Add(new Task() { ID = 3, Name = "Phone", Value = "" });  
       Category1.Tasks.Add(new Task() { ID = 4, Name = "Website", Value = "http://www.pavey.me/" });  
       Category1.Tasks.Add(new Task() { ID = 5, Name = "Comments", Value = "" });  
   
       // category 2  
       Category Category2 = new Category() { Name = "Social Media", Tasks = new List<Task>() };  
       Category2.Tasks.Add(new Task() { ID = 6, Name = "Twitter", Value = "https://twitter.com/matthewpavey" });  
       Category2.Tasks.Add(new Task() { ID = 7, Name = "Facebook", Value = "" });  
       Category2.Tasks.Add(new Task() { ID = 8, Name = "LinkedIn ", Value = "" });  
   
       // category 3  
       Category Category3 = new Category() { Name = "Favorite Websites", Tasks = new List<Task>() };  
       Category3.Tasks.Add(new Task() { ID = 9, Name = "Website", Value = "http://www.pavey.me/" });  
       Category3.Tasks.Add(new Task() { ID = 10, Name = "Website", Value = "https://mysafeinfo.com/" });  
       Category3.Tasks.Add(new Task() { ID = 11, Name = "Website", Value = "" });  
       Category3.Tasks.Add(new Task() { ID = 12, Name = "Website", Value = "" });  
       Category3.Tasks.Add(new Task() { ID = 13, Name = "Website", Value = "" });  
   
       // add to list  
       Categories.Add(Category1);  
       Categories.Add(Category2);  
       Categories.Add(Category3);  
   
       // return  
       return Categories;  
     }  
   
     public void Debug(string Value = "")  
     {  
       pnlDebug.Controls.Add(new LiteralControl(string.Format("<div>{0}</div>", Value)));  
     }  
   
     protected void btnSave_Click(object sender, EventArgs e)  
     {  
       // iterate outer repeater (categories)  
       foreach (RepeaterItem Category in lstCategories.Items)  
       {  
         // iterate inner repeater (tasks)  
         foreach (RepeaterItem Task in ((Repeater)(Category.FindControl("lstTasks"))).Items)  
         {  
           // get reference to controls  
           HiddenField lblID = (HiddenField)Task.FindControl("lblID");  
           HiddenField lblValue = (HiddenField)Task.FindControl("lblValue");  
           TextBox txtValue = (TextBox)Task.FindControl("txtValue");  
   
           // extract values  
           int ID = Convert.ToInt32(lblID.Value);  
           string ValueOriginal = lblValue.Value;  
           string ValueNew = txtValue.Text.Trim();  
   
           // debug  
           Debug(string.Format("ID={0}; ValueOriginal={1}; ValueNew={2}", ID, ValueOriginal, ValueNew));  
         }  
       }  
     }  
   
     protected void btnCancel_Click(object sender, EventArgs e)  
     {  
       Response.Redirect("default.aspx");  
       Response.End();  
     }  
   
     private class Category  
     {  
       public string Name { get; set; }  
       public List<Task> Tasks { get; set; }  
     }  
   
     private class Task  
     {  
       public int ID { get; set; }  
       public string Name { get; set; }  
       public string Value { get; set; }  
     }  
   }  
 }  

The btnSave_Click event is really where everything is happening. We're simply doing a foreach around the lstCategories repeater items. Then inside that loop we're iterating the lstTasks repeater items. It's inside this nested repeater (lstTasks) that we can get reference to the controls (lblID, lblValue, txtValue). From that point it's just a matter of casting the controls, extracting the values, and then using the values. In this case we're just outputting the values for debugging. But this is where you could use the ID and compare the original/new values to determine if you need to apply an update to the record, etc.

Click here to see a full working example of this demo.

Matt Pavey is a Microsoft Certified software developer who specializes in ASP.Net, VB.Net, C#, AJAX, LINQ, XML, XSL, Web Services, SQL, jQuery, and more. Follow on Twitter @matthewpavey

0 comments: