locked
UserControl loses TextBox value when placed inside a MasterPage RRS feed

  • Question

  • User268443118 posted

    When not in a masterPage the user control works great.  Once I place it in a masterPage the value of txtInput is lost on postback. EnabledViewState explicitly set to true, to no avail.  MasterPage is nothing special.

     Note, I am using a modified ajax control, though it doesnt matter if I populate the textbox via the control or by typing it in.
     

    THIS WORKS

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="TestUserControls2.aspx.cs"
        Inherits="Samepage.ExpenseWire.TestUserControls2" %>

    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
    <%@ Register TagPrefix="samepage" TagName="AutoSuggest" src="~/UserControls/SuggestDropDown.ascx" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <cc1:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" ScriptMode="release"
                EnablePageMethods="true">
            </cc1:ToolkitScriptManager>
            <samepage:AutoSuggest ID="AutoSuggestCustomer" runat="server" ControlType="Customer" />
            <asp:TextBox ID="saveField" runat="server"></asp:TextBox>
            <asp:Button OnClick="doSomething" ID="Button1" Text="Save" runat="server" />
        </div>
        </form>
    </body>
    </html>

     

    THIS DOES NOT 

     

    <%@ Master Language="C#" AutoEventWireup="true" CodeFile="Simple.master.cs" Inherits="MasterPages_Simple" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <asp:ContentPlaceHolder ID="Content1" runat="server">
        </asp:ContentPlaceHolder>
        <div>
            <asp:ContentPlaceHolder ID="Content2" runat="server">
            </asp:ContentPlaceHolder>
        </div>
        <div>
            <asp:ContentPlaceHolder ID="Content3" runat="server">
            </asp:ContentPlaceHolder>
        </div>
        </form>
    </body>
    </html>

    <%@ Page Language="C#" MasterPageFile="~/MasterPages/Simple.Master" AutoEventWireup="true"
        CodeFile="TestUserControls.aspx.cs" Inherits="Samepage.ExpenseWire.TestUserControls" %>

    <%@ MasterType VirtualPath="~/MasterPages/EditRightPane.Master" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
    <%@ Register TagPrefix="samepage" TagName="AutoSuggest" src="~/UserControls/SuggestDropDown.ascx" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="Content1" runat="server">
        <cc1:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" ScriptMode="release"
            EnablePageMethods="true">       
        </cc1:ToolkitScriptManager>   
    </asp:Content>
    <asp:Content ID="Content2" ContentPlaceHolderID="Content2" runat="server">
        <samepage:AutoSuggest ID="AutoSuggestCustomer" runat="server" ControlType="Customer" />
        <asp:TextBox ID="saveField" runat="server"></asp:TextBox>
    </asp:Content>
    <asp:Content ID="ButtonContent" ContentPlaceHolderID="Content3" runat="server">
        <asp:Button OnClick="doSomething" ID="Button1" Text="Save" runat="server" />
    </asp:Content>

     CODE BEHIND FOR BOTH PAGES

    using System;
    using System.Collections;
    using System.Configuration;
    using System.Data;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;

    namespace Samepage.ExpenseWire
    {
        public partial class TestUserControls2 : MyBasePage
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    saveField.Text = "";
                    AutoSuggestCustomer.CompanyID = Settings.CompanyId;
                    AutoSuggestCustomer.setSuggestText("45 South Music25506580");
                }
            }

            protected void doSomething(Object sender, EventArgs e)
            {
                string it = AutoSuggestCustomer.SuggestID;
                saveField.Text = it;
            }
        }
    }

    USER CONTROL 

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="SuggestDropDown.ascx.cs"
        Inherits="Controls_SuggestDropDownCtl" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxtoolkit" %>
    <table cellpadding="3" width="100%" cellspacing="0" border="0">
        <tr>
            <td style="width: 100%">
                <asp:TextBox ID="txtInput" CssClass="textInput" runat="server" Width="100%"></asp:TextBox>
                <input id="selectedText" type="hidden" runat="server" />
                <input id="selectedValue" type="hidden" runat="server" />
            </td>
            <td align="right">
                <asp:ImageButton ID="btnSearchImg" runat="server" ImageUrl="~/Graphics/Search_Small.jpg"
                    AlternateText="Search Advanced" TabIndex="-1" />
            </td>
        </tr>
    </table>
    <ajaxtoolkit:AutoCompleteGenericExtender ID="AutoCompleteSuggest" runat="server"
        TargetControlID="txtInput" MinimumPrefixLength="0" CompletionInterval="1000"
        EnableCaching="true" FirstRowSelected="true" ServiceMethod="SuggestDropDownList"
        ServicePath="/Expensewire/UserControls/SuggestDropDown.asmx" CompletionListCssClass="ajax_completionListElement"
        CompletionListItemCssClass="ajax_listItem" CompletionListHighlightedItemCssClass="ajax_highlightedListItem"
        OnClientItemSelected="itemSelected">
    </ajaxtoolkit:AutoCompleteGenericExtender>

    <script type="text/javascript">

    function itemSelected( source, eventArgs ){    
        var hInput = document.getElementById("<%= txtInput.ClientID %>");
        var hText = document.getElementById("<%= selectedText.ClientID %>");
        var hValue = document.getElementById("<%= selectedValue.ClientID %>");
        
        var eText = eventArgs.get_text();
        var eValue = eventArgs.get_value();
        
        hInput.value = eText;
        hText.value = eText;
        hValue.value = eValue;
    }

    </script>

    Friday, May 16, 2008 9:43 AM

Answers

  • User-16411453 posted

    If your making a web based server control, I suggest the following 

    I manually ID my Controls , so master pages don't change them.  There are a hundred ways to do this, This is just one

    panel = New Panel
    panel.Attributes.Add("id", [ID] & "_CreateNewAccount")
    panel.Width = [Width]
    panel.Visible = [Visible]
    panel.Style.Add(HtmlTextWriterStyle.Width, [Width].ToString)
    panel.Style.Add(HtmlTextWriterStyle.TextAlign, "center")
    panel.Style.Add(HtmlTextWriterStyle.Margin, "0px auto")
    Controls.Add(panel)
     

    If you use the template below, start a new CS Class Project, add a new item, Web Custom Control.  The template below is for web forms, and handles postbacks

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.Design;
    using System.Web.UI.WebControls;
    using System.Drawing.Design;
    
    namespace ClassLibrary2
    {
    	[DefaultProperty("Text")]
    	[ToolboxData("&lt;{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
    	public class WebCustomControl1 : WebControl
    	{
    
    		protected override void Render(HtmlTextWriter writer)
    		{
    			base.Render(writer);
    
    			RenderContents(writer);
    			//this renders oninit, createChildControls, and so forth, without calling it.
    		}
    
    
    		protected override void OnInit(EventArgs e)
    		{
    			base.OnInit(e);
    
    			//Place your Control Code here
    			//You have to make objects in code such as textboxes
    			//If your making forms, you should use OnInit, because it handles buttons clicks
    			//and other events, saves your data too on postback, until you clear the data in the control
    			//CreateChildControls can be used, but does not handle click events automatically
    
    
    			Controls.Clear(); //clear out old controls
    			//Create a panel container to hold the contents - FYI Panels are <div></div> tags
    
    
    
    		}
    
    		protected override void OnLoad(EventArgs e)
    		{
    			base.OnLoad(e);
    			//You can place code here that supplements Page.Onload in code behind, if there is a code behind page.
    			//I don''t use code behind pages anymore, I just place the code here.
    
    		}
    		//You can stack those properties here
    		
    
    		[Bindable(true)]
    		[Category("Appearance")]
    		[DefaultValue("")]
    		[Localizable(true)]
    		public string Text
    		{
    			get
    			{
    				String s = (String)ViewState["Text"];
    				return ((s == null) ? String.Empty : s);
    			}
    
    			set
    			{
    				ViewState["Text"] = value;
    			}
    		}
    	}
    }
    
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, May 19, 2008 3:22 PM

All replies

  • User1963151947 posted

    Nothing is jumping out at me from the code, but I don't see the code behind for the UserControl.  One thing you might want to do is put a break point in the user control during the OnLoad or something.  The take a look at the Request.Form collection and see if the value is in there.  That will help to point out whether or not the client is sending the value back to the server.  If it's not in the Request.Form collection, then something on the client end is removing the value before it submits. If it is there, then I would check the code behind of the user control and make sure it isn't doing something wrong.

    Sorry I don't have an answer, but hopefully this helps you get closer to finding it.

    Friday, May 16, 2008 4:05 PM
  • User-16411453 posted

    Masterpages rename the control's id with the prefix ct100 and control's name with ct100$.  There are a thousand ways to overcome this depending on your skill level.

    You should search the keyword ctl00$ in the forum

    you can manually set the id of the control with attributes.add("id", "[ID] & "_controlName") 

    Friday, May 16, 2008 6:46 PM
  • User268443118 posted

    Thanks for the tip on the page load and the request.form.  Unfortunately the value is in the form collection, do you by chance have any further insight?  I hate to hardcode "this.Request.Form["AutoSuggestCustomer$txtInput"]" instead of txtInput.Text

    Debugging (masterpage version) with a breakpoint onload has the following:

             this.Text    ""    string
            this.txtInput.ClientID    "AutoSuggestCustomer_txtInput"    string
            this.Request.Form["AutoSuggestCustomer$txtInput"]    "45 South Music25506580"    string

     If it is not using the masterPage then this.Text == this.Request.Form["AutoSuggestCustomer$txtInput"]

     

    USER CONTROL CODE BEHIND 

     [ValidationPropertyAttribute("Text")]
    public partial class Controls_SuggestDropDownCtl : System.Web.UI.UserControl
    {
        protected const string ColumnName = "Name";
        protected const string ColumnID = "Value";
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Samepage.ExpenseWire.MyBasePage page = this.Page as Samepage.ExpenseWire.MyBasePage;
                CompanyID = page.Settings.CompanyId;
            }
        }

        protected override void OnInit(EventArgs e)    {
            
            if (!IsPostBack)
            {
                //--Set Initial Property Defaults--
                //this.Session["_SuggestControlID"] = txtInput.ClientID;
            }

            base.OnInit(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }



        public string ControlType
        {
            get
            {
                string controlType = "";
                if (this.ViewState["_controlType"] != null)
                {
                    controlType = this.ViewState["_controlType"].ToString();
                }
                return controlType;
            }
            set
            {
                this.ViewState["_controlType"] = value;
                AutoCompleteSuggest.ControlName = value;
                btnSearchImg.OnClientClick = String.Format("OpenSuggestSearch('{0}','{1}'); return false;", txtInput.ClientID, ControlType);
            }
        }

        public int CompanyID
        {
            get
            {
                int compID = 0;
                if (this.ViewState["_companyID"] != null)
                {
                    Int32.TryParse(this.ViewState["_companyID"].ToString(), out compID);
                }
                return compID;
            }
            set
            {
                this.ViewState["_companyID"] = value;
                AutoCompleteSuggest.ContextKey = value.ToString();
            }
        }

        public string Text
        {
            get { return txtInput.Text; }
            protected set { txtInput.Text = value; }
        }

        public void setSuggest(string text, string id)
        {
            this.Text = text;
            this.selectedText.Value = text;
            this.selectedValue.Value = id;
        }
        public void setSuggestText(string text)
        {
            if (text == null || text.Length == 0)
            {
                this.Text = "";
                this.selectedText.Value = "";
                this.selectedValue.Value = "";
                return;
            }

            DataTable dTable = SuggestDropDown.List(CompanyID, ControlType, text, '%');
            if (dTable.Rows.Count > 0 && text.Equals(dTable.Rows[0][ColumnName].ToString()))
            {
                this.Text = text;
                this.selectedText.Value = text;
                this.selectedValue.Value = dTable.Rows[0][ColumnID].ToString();
                return;
            }

            this.Text = "Invalid/Deleted Entry";
            this.selectedText.Value = "Invalid/Deleted Entry";
            this.selectedValue.Value = "";
            return;
        }
        public void setSuggestID(string id)
        {
            if (id == null || id.Length == 0)
            {
                this.Text = "";
                this.selectedText.Value = "";
                this.selectedValue.Value = "";
                return;
            }
            string text = SuggestDropDown.Lookup(CompanyID, ControlType, id);
            this.Text = text;
            this.selectedText.Value = text;
            this.selectedValue.Value = id;
        }

        public bool hasSelectedValue()
        {
            bool hasValue = this.selectedValue.Value != "";
            return hasValue;
        }

        public string SuggestID
        {
            get
            {
                if (this.Text == "")
                    return null;
                if (this.Text == this.selectedText.Value)
                    return this.selectedValue.Value;

                DataTable dt = SuggestDropDown.List(this.CompanyID, this.ControlType, this.Text);
                if (dt.Rows.Count > 0)
                    return dt.Rows[0][ColumnID].ToString();
                return null;
            }
        }

        public bool ReadOnly
        {
            get { return !Enabled; }
            set { Enabled = !value; }
        }

        public bool Enabled
        {
            get { return txtInput.Enabled; }
            set
            {
                txtInput.Enabled = value;
                btnSearchImg.Visible = value;
                AutoCompleteSuggest.Enabled = value;
            }
        }

        public string ClientTextBoxID
        {
            get { return txtInput.ClientID; }
        }

    }

    Monday, May 19, 2008 9:12 AM
  • User1963151947 posted

    Is the clientId for the txtInput the same when you post back with the masterpage and without?

    So far the only reasons I have run into something like this is because the name/clientid of the control changes durning runtime.  This usually happens when you start adding controls dynamically on the server side.  I don't see anywhere that you are doing that.  The other time I have run into this is when the textbox is set to readonly.  If it is readonly on the server side, the .NET framework never sets the text propery on post back. So for example if you have a textbox on your page with readonly set to true, you can set the text property in the code behind to a value and it will return it and render it out to the client.  During postback, it will not set the text property.

    I was looking through again and I didn't see the master page code behind.  Since it is not there, I am going to guess and say that it has some processing in the code behind.  Have you tried to create just a blank master page with nothing in it and put the user control on there to see if it works.  That will point out whether or not it is something in the code of the master page that would be causing it.

    Monday, May 19, 2008 10:22 AM
  • User268443118 posted

    Is the clientId for the txtInput the same when you post back with the masterpage and without?

    So far the only reasons I have run into something like this is because the name/clientid of the control changes durning runtime.  This usually happens when you start adding controls dynamically on the server side.  I don't see anywhere that you are doing that.  The other time I have run into this is when the textbox is set to readonly.  If it is readonly on the server side, the .NET framework never sets the text propery on post back. So for example if you have a textbox on your page with readonly set to true, you can set the text property in the code behind to a value and it will return it and render it out to the client.  During postback, it will not set the text property.

    I was looking through again and I didn't see the master page code behind.  Since it is not there, I am going to guess and say that it has some processing in the code behind.  Have you tried to create just a blank master page with nothing in it and put the user control on there to see if it works.  That will point out whether or not it is something in the code of the master page that would be causing it.

     

     

    client ids are same for with and without.  No dynamic controls nothin, textbox isnt readonly, nothing seems amiss except of course that it doesnt work.  Makes no sense.

    As for the master page, its as simple as it gets: 

    public partial class MasterPages_Simple : System.Web.UI.MasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }

     

    This is the workaround i am probably going to have to use (hate doing workarounds):

    protected override void OnLoad(EventArgs e)
        {
            // Uknown Bug with master page
            // Dont use '_' in the ID of the control or it will not work
            string it = Request.Form[txtInput.ClientID.Replace("_", "$")];
            if (it != null && it != "")
                Text = it;

            base.OnLoad(e);
        }

    Monday, May 19, 2008 10:35 AM
  • User1963151947 posted

    Sorry to say, but as of right now I am stumped.  Maybe someone on the .NET team will see this and try to figure out what is going on in the framework that would cause it.  I opened up the framework with Reflector and see a whole bunch of places where it would cause it to not load it from postback, but nothing where you could easily add a breakpoint and check values out without using reflection.  I hate workarounds also, so I feel your pain.

    Monday, May 19, 2008 11:02 AM
  • User-16411453 posted

    If your making a web based server control, I suggest the following 

    I manually ID my Controls , so master pages don't change them.  There are a hundred ways to do this, This is just one

    panel = New Panel
    panel.Attributes.Add("id", [ID] & "_CreateNewAccount")
    panel.Width = [Width]
    panel.Visible = [Visible]
    panel.Style.Add(HtmlTextWriterStyle.Width, [Width].ToString)
    panel.Style.Add(HtmlTextWriterStyle.TextAlign, "center")
    panel.Style.Add(HtmlTextWriterStyle.Margin, "0px auto")
    Controls.Add(panel)
     

    If you use the template below, start a new CS Class Project, add a new item, Web Custom Control.  The template below is for web forms, and handles postbacks

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.Design;
    using System.Web.UI.WebControls;
    using System.Drawing.Design;
    
    namespace ClassLibrary2
    {
    	[DefaultProperty("Text")]
    	[ToolboxData("&lt;{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
    	public class WebCustomControl1 : WebControl
    	{
    
    		protected override void Render(HtmlTextWriter writer)
    		{
    			base.Render(writer);
    
    			RenderContents(writer);
    			//this renders oninit, createChildControls, and so forth, without calling it.
    		}
    
    
    		protected override void OnInit(EventArgs e)
    		{
    			base.OnInit(e);
    
    			//Place your Control Code here
    			//You have to make objects in code such as textboxes
    			//If your making forms, you should use OnInit, because it handles buttons clicks
    			//and other events, saves your data too on postback, until you clear the data in the control
    			//CreateChildControls can be used, but does not handle click events automatically
    
    
    			Controls.Clear(); //clear out old controls
    			//Create a panel container to hold the contents - FYI Panels are <div></div> tags
    
    
    
    		}
    
    		protected override void OnLoad(EventArgs e)
    		{
    			base.OnLoad(e);
    			//You can place code here that supplements Page.Onload in code behind, if there is a code behind page.
    			//I don''t use code behind pages anymore, I just place the code here.
    
    		}
    		//You can stack those properties here
    		
    
    		[Bindable(true)]
    		[Category("Appearance")]
    		[DefaultValue("")]
    		[Localizable(true)]
    		public string Text
    		{
    			get
    			{
    				String s = (String)ViewState["Text"];
    				return ((s == null) ? String.Empty : s);
    			}
    
    			set
    			{
    				ViewState["Text"] = value;
    			}
    		}
    	}
    }
    
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, May 19, 2008 3:22 PM