To recap the situation - you need to do a FindControl of a control on a page from a child control, however -
- Your project has a MasterPage, in which case
this.Page
seems to not work, and we use this.Parent
instead
- Your "target" control is inside a PlaceHolder, which itself is inside a ContentPlaceHolder, so it's not as simple as just
this.Parent.FindControl()
- Your child ASCX control that is trying to find the "target" control, in this case a textbox, is actually in ANOTHER ContentPlaceHolder, so again, this.Parent.Parent or whatever will not work.
Since you mentioned after my initial this.Parent
answer about the controls being in a different ContentPlaceHolder from each other, and in another child control, it complicates your query a bit.
Based on these criteria, and the fact that you at least know the contentPlaceHolder control which contains (somewhere inside of it) your target TextBox, here's some code I wrote that works for me in a new ASP.net Web Forms application:
It recursively checks controls collection of the ContentPlaceHolder you pass to it, and finds your control.
Just pass the ControlID and ContentPlaceHolderID, and it will recursively find it.
This code is a replacement for my original one below with the same project, located inside of ChildControl.ascx.cs file:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Linq;
using System.Collections.Generic;
namespace FindControlTest
{
public partial class ChildControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var textBoxTest = FindControlInContentPlaceHolder("TextBoxTest", "FeaturedContent") as TextBox;
Response.Write(textBoxTest.Text);
Response.End();
}
private Control FindControlInContentPlaceHolder(string controlID, string contentPlaceHolderID)
{
if (null == this.Page ||
null == this.Page.Master)
{
return null;
}
var contentPlaceHolder = this.Page.Master.FindControl(contentPlaceHolderID);
var control = getChildControl(controlID, contentPlaceHolder);
return control;
}
private Control getChildControl(string controlID, Control currentControl)
{
if (currentControl.HasControls())
{
foreach(Control childControl in currentControl.Controls)
{
var foundControl = childControl.FindControl(controlID);
if (null != foundControl)
{
return foundControl;
}
else
{
return getChildControl(controlID, childControl);
}
}
}
return null;
}
}
}
Note:
I tried this in a few events and even on Init() I was able to get the TextBox value
If you are seeing a null it is likely due to an incorrect ID being passed or a situation I didn't encounter yet. If you edit your question with additional info (as there has been a lot of it) and show what variable is null, it can be resolved.
Note that I added some complexity to my MasterPage, such as a PlaceHolder inside a Panel, and then put the ContentPlaceHolder in there, and the code still works. I even compiled for .net 4.5, 4.0, 3.5, and 3.0 thinking maybe FindControl works differently with MasterPages, but still it works every time. You may need to post some additional MarkUp if you still get a null.
The Rest of the Test Project
The Page (based on default MasterPage)
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="FindControlTest._Default" %>
<%@ Register TagName="ChildControl" TagPrefix="uc1" Src="~/ChildControl.ascx" %>
<asp:Content runat="server" ContentPlaceHolderID="FeaturedContent">
<asp:PlaceHolder ID="PlaceHolderTest" runat="server">
<asp:TextBox ID="TextBoxTest" Text="Hello!" runat="server"/>
</asp:PlaceHolder>
</asp:Content>
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
<uc1:ChildControl id="ChildControlTest" runat="server" />
</asp:Content>
I added a control called ChildControl.ascx that only has this in it:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ChildControl.ascx.cs" Inherits="FindControlTest.ChildControl" %>
Hello child!
The result is "Hello!" on the page.