Find a control in a TemplateField programmatically
When you add a DetailsView or GridView control to your page, you may need to programmatically access that control in the code behind. You might look at the System.Web.UI.Page object and see it has a FindControl (http://msdn2.microsoft.com/en-us/library/31hxzsdw.aspx) method built in for you. If you thought that you could get ANY control on the page...
You would be wrong.
Unfortunately, this function does not recursively search all controls on the page. Instead, it only searches the immediate child controls of the page (ie: Form, etc.) The problem is that if you have a DetailsView control on the page and want to get at a template field in the control, you have to search the DetailsView control's child controls for this item.
You might try instead to search the Page.Form.Controls collection but again, you have the same problem because the form control collection only contains the direct child controls on the page. In the case below, the only control it contains would be "DetailsView1". Here's what the page looks like with a DetailsView1 control and a TemplateField called "Name":
<body>
<form id="form1" runat="server">
<div>
<asp:DetailsView ID="DetailsView1" runat="server"
AutoGenerateRows="False"
DataSourceID="ObjectDataSource1">
<Fields>
<asp:TemplateField HeaderText="Name" SortExpression="Name">
<ItemTemplate>
<asp:Label ID="lblName" runat="server" Text='<%# Bind("Name") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("Name") %>'></asp:TextBox>
</EditItemTemplate>
<InsertItemTemplate>
<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("Name") %>'></asp:TextBox>
</InsertItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
</div>
</form>
</body>
There are a couple of ways you can still access this control programmatically. First, let's "view source" to see how these controls are named when the page generates them:
<table cellspacing="0" rules="all" border="1" id="Table1" style="border-collapse:collapse;">
<tr>
<td>Name</td>
<td>
<input name="DetailsView1$txtName" type="text" value="My Value 1" id="DetailsView1_txtName" />
</td>
</tr>
</table>
Notice that the page names the "txtName" control as: "DetailsView1$txtName". This follows for multiple rows in the control. The ASP.NET page generation builds the name as follows:
[Parent Container Control Name]$[Child Control Name]
We have to recursively traverse the control tree to look at each control in each container control to find this TextBox. A nice shortcut that isn't well documented is that you can reference the control directly using the FindControl method with this syntax:
TextBox txtName = (TextBox)Page.Form.FindControl("DetailsView1:txtName");But a lot of the time you don't even know the container control and just want the control globally across all controls on the page. In that case, we can use recursion to loop through all elements on the page and find the control by it's ID. Here's a simple method that traverses the Page.Form controls collection and returns the control with the specified ID:
private Control FindControlRecursive(Control ctlRoot, string sControlId)
{ // if this control is the one we are looking for, break from the recursion // and return the control. if (ctlRoot.ID == sControlId) { return ctlRoot;}
// loop the child controls of this parent control and call recursively.foreach (Control ctl in ctlRoot.Controls)
{Control ctlFound = FindControlRecursive(ctl, sControlId);
// if we found the control, return it.if (ctlFound != null)
{ return ctlFound;}
}
// we never found the control so just return null.return null;
}
You would use this method with the following lines of code:
// search for the control by it's ID.Control controlToFind = FindControlRecursive(DetailsView1, "txtName");// make sure something was returned (ie: not null).if (controlToFind != null)
{ // cast the control to a TextBox.TextBox txtNameFound = (TextBox)controlToFind;
// do something with the TextBox control.}
One thing to remember is that recursion can be slow so you only want to use the second method when you cannot use the first. Also, the recursive method should be called with the lowest level Control container parent you have. In other words, calling it on the Page.Form object could/should be slower than calling it on the DetailsView control which has fewer controls to traverse.
Popular Articles
Last viewed:
- Installing the SMTP Service on Windows 2003 Server
- Data Access Layer using SqlDataReader and C#
- SQL Create Table Add Description to Column
- How to Highlight the Day in the ASP.NET Calendar Control with the SelectedDate Property
- Clustered Index vs. Non-Clustered Index in SQL Server
- How to Install the ASP.NET AJAX Control Toolkit
Recent comments
- jkll
13 hours 45 min ago - Thank You
1 day 13 hours ago - Another approach
3 days 14 hours ago - Issue
4 days 4 hours ago - thanks
4 days 14 hours ago - Calendar date time
4 days 20 hours ago - Nice Explanation
5 days 29 min ago - ramya
1 week 21 hours ago - thank a lot
1 week 1 day ago - Very useful, but...
1 week 4 days ago

I still have not access to my hyperlink which is inside of templ
I implemented your code in my code behind to have access to hyperlink which is inside a templatefield of detailsview control but your code returns null
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="products.aspx.cs" Inherits="products" %>
<%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="asp" %>
DataKeyNames="GROUPNAME" ForeColor="#333333" GridLines="None"
>
GridLines="None" AutoGenerateColumns="False" DataKeyNames="SETNUM"
onselectedindexchanged="GridView2_SelectedIndexChanged">
DataSourceID="SqlDataSource3" EnableModelValidation="True" ForeColor="#333333"
GridLines="None" Caption="مجموعه تجهيزات" CaptionAlign="Top"
onprerender="DetailsView1_PreRender"
ToolTip="با کليک کردن روي اعداد پايين صفحه ميتوانيد تمام کالاهاي مجموعه را مشاهده نماييد"
Width="75%" ondatabinding="DetailsView1_DataBinding"
ondatabound="DetailsView1_DataBound">
SelectCommand="SELECT * FROM [EQUIP] WHERE ([SETNUM] LIKE '%' + @SETNUM + '%') ORDER BY [CATNO]">
SelectCommand="SELECT DISTINCT [GROUPNAMEF], [GROUPNAME] FROM [LABSET] ORDER BY [GROUPNAMEF]">
SelectCommand="SELECT [SETNAME], [SETNAMEF], [SETNUM] FROM [LABSET] WHERE ([GROUPNAME] = @GROUPNAME)">
PropertyName="SelectedValue" Type="String" />
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class products : System.Web.UI.Page
{
string sJavaScr = "function SizeIMGS() {\n" +
"for (j =3; j < document.images.length; j++) {\n" +
"//if(j%6==0)\n" +
"SizeIMG(document.images[j], 175);}\n" +
"return;}\nfunction SizeIMG(img1, newW) {\n" +
"w = img1.width;h = img1.height;if (h == 0) h = newW;" +
"k = w / newW;img1.height = h / k;img1.width = newW;}\nSizeIMGS();";
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Button1.Visible = false;
Button2.Visible = false;
string slang=Request.QueryString["lang"];
if (slang == "en" || slang == "EN")
{
Button2.Text = "Show Lab Sets";
Button1.Text = "Show Lab Sets";
DetailsView1.Fields[1].HeaderText = "Cat. No.";
DetailsView1.Fields[2].HeaderText = "Product Name";
DetailsView1.Fields[3].HeaderText = "Standards";
DetailsView1.Fields[4].HeaderText = "Photo";
DetailsView1.Fields[5].HeaderText = "Description";
DetailsView1.Fields[6].HeaderText = "Video";
DetailsView1.Fields[7].HeaderText = "Delivery Time";
//DetailsView1.Fields[8].HeaderText = "Brochure";
DetailsView1.Fields[9].HeaderText = "Manual";
DetailsView1.Fields[10].HeaderText = "Enquiry";
DetailsView1.Fields[11].HeaderText = "More Info";
DetailsView1.Caption = "Equipments of This Set:";
BoundField bfr1 = (BoundField)DetailsView1.Fields[2];
bfr1.DataField = "TITLE";
bfr1.HeaderText = "Product Name";
bfr1.ReadOnly = true;
BoundField bfr5 = (BoundField)DetailsView1.Fields[5];
bfr5.DataField = "DESC";
bfr5.HeaderText = "Specifications";
bfr5.ReadOnly = true;
HyperLinkField bfr8 = (HyperLinkField)DetailsView1.Fields[8];
bfr8.DataNavigateUrlFields=new string[] {"BRURL"};
bfr8.DataTextField = "BRURL";
bfr8.HeaderText = "Brochure";
HyperLinkField bfr9 = (HyperLinkField)DetailsView1.Fields[9];
bfr9.DataNavigateUrlFields = new string[] { "MNURL" };
bfr9.DataTextField = "MNURL";
bfr9.HeaderText = "Manual";
//TemplateField bfr10 = (TemplateField)DetailsView1.Fields[10];
// bfr10.ItemTemplate=
//
// HyperLink hplnk = (HyperLink)DetailsView1.Rows[10].Cells[0].FindControl("HyperLink_Quote");
//if (hplnk.NavigateUrl != "")
//{
// string su = hplnk.NavigateUrl;
// su.Replace("fa", "en");
// hplnk.NavigateUrl = su;
//}
//changing gridview fields
BoundField Grid_b2=(BoundField)GridView1.Columns[0];
Grid_b2.DataField = "GROUPNAME";
Grid_b2.HeaderText = "Laboratories List"; //"";
CommandField Grid_b3 = (CommandField)GridView1.Columns[2];
//Grid_b3.DataField = "GROUPNAME";
Grid_b3.SelectText = "Show Category"; //"";
//changing gridview fields
BoundField Grid_b4 = (BoundField)GridView2.Columns[1];
Grid_b4.DataField = "SETNAME";
Grid_b4.HeaderText = "TEST SET SNAME";
CommandField Grid_b5 = (CommandField)GridView2.Columns[3];
//Grid_b3.DataField = "GROUPNAME";
Grid_b5.SelectText = "Show Products"; //"";
mytable.Attributes["Dir"] = "ltr";
}
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void DetailsView1_PreRender(object sender, EventArgs e)
{
Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "SCRIPT", sJavaScr, true);
// GridView1.Visible = false;
// GridView2.Visible = false;
// Button1.Visible = true;
// Button2.Visible = true;
// DetailsView1.Visible = true;
if (DetailsView1.DataItemCount > 0)
{
Button1.Visible = true;
Button2.Visible = true;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
GridView1.Visible = true;
GridView2.Visible = true;
Button1.Visible = false;
Button2.Visible = false;
// DetailsView1.Visible = false;
}
protected void Button2_Click(object sender, EventArgs e)
{
Button1_Click(sender, e);
}
protected void GridView2_SelectedIndexChanged(object sender, EventArgs e)
{
GridView1.Visible = false;
GridView2.Visible = false;
}
private Control FindControlRecursive(Control ctlRoot, string sControlId)
{
// if this control is the one we are looking for, break from the recursion
// and return the control.
if (ctlRoot.ID == sControlId)
{
return ctlRoot;
}
// loop the child controls of this parent control and call recursively.
foreach (Control ctl in ctlRoot.Controls)
{
Control ctlFound = FindControlRecursive(ctl, sControlId);
// if we found the control, return it.
if (ctlFound != null)
{
return ctlFound;
}
}
// we never found the control so just return null.
return null;
}
protected void DetailsView1_DataBound(object sender, EventArgs e)
{
}
protected void DetailsView1_DataBinding(object sender, EventArgs e)
{
// search for the control by it's ID.
Control controlToFind = FindControlRecursive(DetailsView1, "DetailsView1:HyperLink_Quote");
// make sure something was returned (ie: not null).
if (controlToFind != null)
{
// cast the control to a TextBox.
HyperLink hl = (HyperLink)controlToFind;
hl.Text = "do something!";
// do something with the TextBox control.
}
else
DetailsView1.Visible = false;
}
}
can anybody help me?
FindControlRecursive
Nice post! My own FindControlRecursive helped me out many times. Especially, when I deal with MasterPages. For example, one of such usage is shown in my post here – http://dotnetfollower.com/wordpress/2010/12/sharepoint-add-onchange-attribute-to-dropdownchoicefield/.
Thank you!
Thank you!
Solution was very hard to find.
Thanks a lot!
Works great..problem solved!!
I have been trying for hours to solve this issue, but without any success. This method just works. Thanks a ton!!
Thank you very much
No how would you get the value once the control is found ?
good working
very nices info
thanks
Great! Thanks...
This has been racking my brain for hours!
A nice shortcut that isn't well
A nice shortcut that isn't well documented is that you can reference the control directly using the FindControl method with this syntax:
TextBox txtName = (TextBox)Page.Form.FindControl("DetailsView1:txtName");
Nice. Thanks!
Thanks for writing
Thanks for writing this.
The blog is helpfull...visit also
The blog is helpfull...
Extension
The Same Method with Generic Type and Extension Method
public static T FindControlRecursive(this Control.ControlCollection controls, Control control, string controlName) where T : Control
{
if (control.Name == controlName)
{
T returnControl = control as T;
return returnControl;
}
foreach (Control ctrl in control.Controls)(ctrl, controlName);
{
T findControl = controls.FindControlRecursive
if (findControl != null)
{
return findControl;
}
}
return null;
}
Best Regards
Suleyman Ozturk