bjh
bjh

Reputation: 59

Accessing control from content page with nested master pages

I'm really struggling with this. The problem is only with the content pages.
I am trying to access a Text Box value from one content page ("Page1.aspx") in another content page ("Page2.aspx"). I'm not sure whether it is relevant that they are the children of nested master pages, but I thought I'd throw it in.

Page1.aspx is a basic form with text boxes and a submit button. The text box in Page1.aspx is called "tbFirst". The submit button has the following code:

<asp:Button ID="Button1" runat="server" Text="New Member Form" PostBackUrl="Page2.aspx"/>    

Page2.aspx is a new form which should be populated with a textbox value from the previous page. The second line show <%@ PreviousPageType VirtualPath="~/Page1.aspx" %>
For testing purposes I am using a label ("lblResult") to display my results.

Codebehind looks like this:

        if (PreviousPage != null)
        {
            TextBox SourceTextBox =
                (TextBox)PreviousPage.FindControl("tbFirst");
            if (SourceTextBox != null)
            {
                lblResult.Text = SourceTextBox.Text;
            }
            else
            {
                lblResult.Text = "No text found";
            }  
        }
        else
            {
            lblResult.Text = "No Control found";
            }
        }
        }

The problem is that the label text in Page2.aspx says "No text found".

I think that's all the relevant info. Anyone got any ideas? I've spent the whole afternoon trawling the forums and nothing I've tried works.

Upvotes: 2

Views: 3562

Answers (2)

Tim Schmelter
Tim Schmelter

Reputation: 460288

I'm not sure whether it is relevant that they are the children of nested master pages, but I thought I'd throw it in.

The MasterPage is exactly what's causing this issue. You cannot find a control on a page with MasterPage by using Page.FindControl("ControlID"), because the Page is not the NamingContainer of the TextBox but the ContentPlaceholder. The only control in the page's ControlCollection with MasterPage is the MasterPage itself.

Reason: I've recently answered a question that describes this behaviour.

Here are some ways how you can access the TextBox from Page2:

  1. You might have luck with following approach(the most direct FindControl way):

    Page.Master.FindControl("ContentPlaceHolder1").FindControl("tbFirst");
    
  2. Another, better approach would be to provide a public property in Page1 that returns tbFirst.Text. Then you could access it in the following way from Page2:

    if (PreviousPage != null && PreviousPage is Page1){
        lblResult.Text = ((Page1)PreviousPage).TbFirstText;
    }
    
  3. You could also add the Text as URL-Parameter, so that it's not required that Page2's PreviousPage is Page1.

  4. Last but not least. If you use Server.Transer with preserveForm set to tue, you would be able to retrieve the value of the original page TextBox control by referencing Request.Form("TbFirst").

Note: I don't recommend a recursive FindControl approach(starting from MasterPage), because it would also hardwire both pages and would be

  • a cause of nasty errors
  • slow
  • untransparent

Upvotes: 3

Chuck Savage
Chuck Savage

Reputation: 11955

Try using FindControlRecursive(this.Master, "tbFirst") from this class.

(Put this class in App_Code)

using System.Web;
using System;
using System.Web.UI;
using System.Web.UI.WebControls;


/// <summary>
/// Summary description for ControlHelper
/// </summary>
public static class ControlHelper
{
    // Example: HtmlForm form = ControlHelper.FindControlRecursive(this.Master, "form1") as HtmlForm;
    /// <summary>
    /// Finds a Control recursively. Note finds the first match and exits
    /// </summary>
    /// <param name="ContainerCtl"></param>
    /// <param name="IdToFind"></param>
    /// <returns></returns>
    public static Control FindControlRecursive(this Control Root, string Id)
    {
        if (Root.ID == Id)
            return Root;

        foreach (Control Ctl in Root.Controls)
        {
            Control FoundCtl = FindControlRecursive(Ctl, Id);
            if (FoundCtl != null)
                return FoundCtl;
        }

        return null;
    }

    //ModifyControl<TextBox>(this, tb => tb.Text = "test");
    public static void ModifyControl<T>(this Control root, Action<T> action) where T : Control
    {
        if (root is T)
            action((T)root);
        foreach (Control control in root.Controls)
            ModifyControl<T>(control, action);
    }
}

Upvotes: 0

Related Questions