why a multiline textbox (inside a user control) is not holding its value after a postback? - asp.net

I have a user control that have a gridview, buttons and a multi-line textbox for comments.
When the page posts back, Gridview is behaving normaly (its controls keeps their values after postback). However, the Comment textbox is always empty, no matter what I do.
protected void Page_Load(object sender, EventArgs e)
{
//This code is in the user ciontrol.
if (!IsPostBack)
{
string test = this.txtDepartmentComments.Text;
}
}
I put a break point at that line and the value is always empty. I've tried also to set the value in the code behind like:
protected void Page_Load(object sender, EventArgs e)
{
//This code is in the user ciontrol.
if (!IsPostBack)
{
this.txtDepartmentComments.Text = "Test!";
}
}
But when the page loads, the control remain empty.
Any idea why this is hapenning?
EDIT
This the ascx code (i.e. user control)
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns = "false" >
</asp:GridView>
<asp:TextBox ID="txtComments" runat="server" Columns="45" TextMode= "MultiLine"/>
<asp:Button ID="btnComplete" runat="server" Text="Completed"/>
And thid id the aspx (i.e. the parent page)
<asp:Repeater ID="rpNewHire" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<user:MyUserControl ID = "MyUserControl1" runat = "server"
DepartmentID= '<%# Eval("DepID")%>'><user:MyUserControl />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>

if(!IsPostBack) is for reading values from controls after postback, you are trying to read text box value on initial load which will always be empty, remove the '!' from your condition. Also it is hard to debug your issue with out the aspx page contents, try posting the design part as well in your question.
EDIT
Your user tag is not well formatted inside repeater, it is missing closing tag and runat attribute
<user:MyUserControl runat="server" ID = "MyUserControl1" DepartmentID= '<%# Eval("DepID")%>'></user:MyUserControl>
Controls inside repeater cannot be accessed directly, you have to loop through the rows of the repeater and find your child controls and then try reading values from them, that after you bind some data to the repeater.
Check this http://msdn.microsoft.com/en-us/magazine/cc163780.aspx

Page's IsPostBack and each user controls' IsPostBack are not same.
When a user control is posted back, that particular control's IsPostBack is true, but other user controls' IsPostBack are still false.
You can use explicitly !Page.IsPostBack inside a user control to check whether its parent page is posted back or not.
if(!Page.IsPostBack){
// do something
}
Dynamically Loaded Control can not maintain values at PostBack? It is not directly related to your question, but it might be useful for you.

Related

Why do my dynamically added controls loose their values after Postback?

To ask my question I have created an aspx file containing a Button and a DataList with an SqlDataSource:
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
<asp:DataList ID="DataList1" runat="server" DataKeyField="a"
DataSourceID="SqlDataSource1" >
<ItemTemplate>
a:
<asp:Label ID="aLabel" runat="server" Text='<%# Eval("a") %>' />
<br />
b:
<asp:Label ID="bLabel" runat="server" Text='<%# Eval("b") %>' />
<br />
</ItemTemplate>
</asp:DataList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:probaConnectionString %>"
SelectCommand="SELECT [a], [b] FROM [PROBA_TABLE]"></asp:SqlDataSource>
In my code behind I add TextBoxes to the Items of the DataList. I add to every Item a TextBox in the Page_Load, and another TextBox in the Button Click eventhandler as well.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
foreach (DataListItem item in DataList1.Items)
{
item.Controls.Add(new TextBox());
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
foreach (DataListItem item in DataList1.Items)
{
item.Controls.Add(new TextBox());
}
}
}
}
This works fine except one thing. When I click the Button, the TextBoxes which were created in the Page_Load keep their Text value, but the TextBoxes which were created in the Button1_Click lose their Text values. My real problem is more complicated than this, but I think solving this would help me a lot.
Each control that should receive data from page ViewState should be instantiated in Init or Load event handlers, because ViewState is persisted to controls BEFORE Click, Change and the rest control events (those events are triggered when ViewState changes are detected, so ViewState must be read before Click event is fired).
So the process should look like:
OnInit (static controls get created)
Static control content is deserialized from ViewState
OnLoad (create dynamic controls, in your case textboxes that you created in last Postback)
Dynamic control content is deserialized from ViewState
Click, Change and other events are fired according to changes detected comparing POST data and ViewState data
Suggestions:
You can use hidden fields to save additional status information, and then in OnLoad you can read that info to recreate dynamically created controls.
Also, you should explicitly set ID property of your textboxes so that values can be properly persisted back, don't rely on ASP.Net.
the http by default is stateless that means after your request is processed the server keeps no data or info of the request
but the values in the form need to be persisted in special cases when there is an error
suppose you fill up a long form and then post it back to the server only to get an error message and all the filled up values are gone. wouldn't that be annoying
so what asp.net does behind the scenes that it keeps a string in the page hidden that has information about all the server controls and their ids
so when you post a form back the Page class is created and the values that are posted back and binded in the specific controls because the Page class is being created in every request the pageLoad event is run and controls created in the PageLoad are then present values corresponding to their ids are put into them unlike the controls that are being created on button click till the button_click event is run that viewstate has already been deseralized and values are filled into them

Getting an Instance of Dropdown list when clicking update on GridView in Asp.Net

I have a GridView with more than 30 columns. Most are plain controls but for some I have added a template control (DropDownList, Calendar and CheckBox control). Here is the aspx code for the control in question
<asp:TemplateField HeaderText="Field1 Caption" SortExpression="Field1">
<ItemTemplate>
<asp:Label ID="lblConstructionArea" runat="server" Text='<%# Eval("Field1") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlField1" EnableViewState="true" runat="server"></asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
I wanted a dropdown to be shown on the column when a user clicked on Edit. So I add this code (and the above EditItemTemplate)
protected void gvData_RowEditing(object sender, GridViewEditEventArgs e)
{
string fieldOne = CommonUtils.ExtractControlValue(e,"lblField1",gvData);
gvData.SelectedIndex = e.NewEditIndex;
gvData.EditIndex = e.NewEditIndex;
gvData.DataBind();
BindGridDropDownData(e, CommonUtils.GetConstructionAreas() ,"ddlConstructionArea", constructionArea, "Field1", fieldOne);
}
In the above code I am getting the current available and passing it to another method so that when the dropdown is displayed the selected index can be shown accurately. After this I do a change on the dropdownlist and click on the "Update button" on the GridView and the following event is triggered
protected void gvData_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
int rowEditIndex = e.RowIndex;
GridViewRow gRow = gvData.Rows[rowEditIndex];
DropDownList ddlConstructionArea = (DropDownList) gvData.Rows[rowEditIndex].FindControl("ddlConstructionArea"); //This does not work
ddlConstructionArea = (DropDownList)gRow.FindControl("ddlConstructionArea");//This does not work
ddlConstructionArea = (DropDownList)gvData.Rows[rowEditIndex].Cells[7].FindControl("ddlConstructionArea");//this does not work either
gvData.EditIndex = -1;//this works and the text boxes disappear
gvData.DataBind();//this works and the old data shows up on the gridview
}
I am curious as to how to do an update on a Grid where I have the binding is runtime.
Actually in the markup, you have given ID of dropdownlist as ddlField1 and in codebehind, you are reffering it as ddlConstructionArea. Is this is what causing the update not to function?
The problem was with the way the grid was being bound. I had written code to refresh the grid on page load and anytime I clicked on the Edit button the page was being refreshed and the grid binding was getting triggered instead of the updating event. I removed the code refreshing the grid on page load and put it in the places where it is needed and the order of events were getting triggered the way I would want it to and the update worked perfectly without a problem.

Controls within .ascx are not displaying their new value on postback

This seems like an elementary issue but it has me stumped.
I have a main page which loads a custom control (.ascx) on page_load.
This custom control has two fields. One of them being a dropdownlist and the other being a text box. When the dropdownlist changes value it triggers a post back, some logic is executed server side and a value is generated for the textbox. I stepped through the code and the value is created and assigned correctly. However, when the page is rendered the value does not change.
If I change the textbox value to "QQQ" and trigger the postback, "QQQ" stays in the textbox so I can verify viewstate is working.
Is there any reason why the generated value is not being displayed in the form on postback. This process works fine on the initial page load.
.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
string ascxPath = #"~/_CONTROLTEMPLATES/TRC_BITS.ascx";
TRC_BITS control = Page.LoadControl(ascxPath) as TRC_BITS;
phForm.Controls.Add(control);
}
.ascx
<asp:TextBox ID="message" runat="server" TextMode="MultiLine" /><br/>
<asp:DropDownList ID="year" runat="server" AutoPostBack="true">
<asp:ListItem Text="2011">2011</asp:ListItem>
<asp:ListItem Text="2012">2012</asp:ListItem>
<asp:ListItem Text="2013">2013</asp:ListItem>
</asp:DropDownList>
.ascx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
year.SelectedValue = DateTime.Now.Year.ToString();
}
if (year.SelectedValue == 2012)
message.Text = "ABC";
else
message.Text = "XYZ";
}
Because you're adding these controls to the page dynamically, you need to assign an ID to the user control. Make sure to assign the same ID to the controls every time the page is posted back, and the fields will be repopulated from ViewState.
Also, as Shai suggested, it would be more appropriate if you loaded the controls during OnInit instead of Page_Load. The situation is a little different with user controls, but in general you want to add your dynamic content before the LoadViewState method is executed.
If you're looking for something to take the pain out of persisting dynamic content, I would suggest taking a look at the DynamicControlsPlaceHolder.
Because you are adding the controls dynamically, you need to add them during the page's oninit event.
Try it, believe me. Go for it. Yalla.

ASP.NET AJAX Toolkit - CalendarExtender is reset on Postback

I have an ASP.NET page that has two input elements:
A TextBox that is ReadOnly. This TextBox is the TargetControl of a CalendarExtender
A DropDownList with AutoPostBack=true
Here is the code:
<table border="0" cellpadding="0" cellspacing="0">
<tr><td colspan="2">Date:</td></tr>
<tr><td colspan="2">
<asp:TextBox ID="dateTextBox" runat="server" ReadOnly="true" />
<ajax:CalendarExtender ID="datePicker" runat="server" Format="MM/dd/yyyy" OnLoad="datePicker_Load" TargetControlID="dateTextBox" />
</td></tr>
<tr><td colspan="2">Select an Option:</td></tr>
<tr>
<td>Name: </td>
<td><asp:DropDownList ID="optionsDropDownList" runat="server" AutoPostBack="true"
OnLoad="optionsDropDownList_Load"
OnSelectedIndexChanged="optionsDropDownList_SelectedIndexChanged"
DataTextField="Name" DataValueField="ID" />
</td></tr>
<tr><td><asp:Button ID="saveButton" runat="server" Text="Save" OnClick="saveButton_Click" /></td></tr>
</table>
When the DropDownList posts back, the date selected by the user with the datePicker is reset to the current date. In addition, if I look at the Text property of dateTextBox, it is equal to string.Empty.
How do I preserve the date that the user selected on a PostBack?
Certainly you must do as others have already suggested: set readonly field dynamically rather than in markup, and make sure you are not accidentally resetting the value in Page_Load() during postbacks...
...but you must also do the following inside Page_Load(), because the CalendarExtender object has an internal copy of the date that must be forcibly changed:
if (IsPostBack) // do this ONLY during postbacks
{
if (Request[txtDate.UniqueID] != null)
{
if (Request[txtDate.UniqueID].Length > 0)
{
txtDate.Text = Request[txtDate.UniqueID];
txtDateExtender.SelectedDate = DateTime.Parse(Request[txtDate.UniqueID]);
}
}
}
The fact that the text box is read only appears to be causing this problem. I duplicated your problem using no code in any of the bound events, and the date still disappeared. However, when I changed the text box to ReadOnly=False, it worked fine. Do you need to have the textbox be read only, or can you disable it or validate the date being entered?
EDIT: OK, I have an answer for you. According to this forum question, read only controls are not posted back to the server. So, when you do a postback you will lose the value in a read only control. You will need to not make the control read only.
protected void Page_Load(object sender, EventArgs e)
{
txt_sdate.Text = Request[txt_sdate.UniqueID];
}
If you want the textbox contents remembered after the postback and still keep it as readonly control, then you have to remove the readonly attribute from the markup, and add this in the codebehind pageload:
protected void Page_Load(object sender, EventArgs e){
TextBox1.Attributes.Add("readonly", "readonly");
// ...
}
The solution to the issue is making use of Request.Form collections. As this collection has values of all fields that are posted back to the server and also it has the values that are set using client side scripts like JavaScript.
Thus we need to do a small change in the way we are fetching the value server side.
C#
protected void Submit(object sender, EventArgs e)
{
string date = Request.Form[txtDate.UniqueID];
}
I suspect your datePicker_Load is setting something and not checking if it's in a postback. That would make it happen every time and look like it was 'resetting'.
In stead of setting ReadOnly="False", set Enabled="False". This should fix your issue.
#taeda's answer worked for me. FYI, if someone uses enabled = "false" instead of readonly = "true" wont be able to use that answer, because Request[TxtDate.UniqueId] will throw a null exception.
It is not a problem of Preserving,after setting readonly = true the value of the particular textbox doesn't be returned back to server
so
Use contentEditable="false" and made readonly = false
that would prevent value is being entered other than Calendar Extender selection also returns the value of the Text box back to the server

ASP.NET: "Object Required" when repeating LinkButtons in an UpdatePanel

I have an UpdatePanel which has a Repeater repeating LinkButtons. When I click a LinkButton, the page does a partial postback, then I get a javascript error: "Object required". I tried debugging the javascript, but couldn't get a call stack. If I remove the UpdatePanel, the LinkButtons do a full postback, and they disappear from the page. How can I get this UpdatePanel to work?
<ajax:UpdatePanel ID="wrapperUpdatePanel" runat="server" UpdateMode="Always">
<ContentTemplate>
<asp:Repeater ID="endpointRepeater" runat="server" OnItemDataBound="EndpointDataBound">
<HeaderTemplate>
<div class="sideTabs">
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:LinkButton ID="endpointLink" runat="server" OnClick="EndpointSelected" />
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</div>
</FooterTemplate>
</asp:Repeater>
</ContentTemplate>
</ajax:UpdatePanel>
binding code:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.SelectedEndpoint = Factory.Get<IEndpoint>(Enums.EndPoints.Marketing);
}
IEndpointCollection col = EndpointCollection.GetActivelySubscribingEndpointsForPart(this.Item);
if (this.Item.IsGdsnItem)
col.Add(Factory.Get<IEndpoint>(Enums.EndPoints.Gdsn));
if (col.Count > 0)
col.Insert(0, Factory.Get<IEndpoint>(Enums.EndPoints.Marketing));
this.endpointRepeater.DataSource = col;
this.endpointRepeater.DataBind();
if (this.endpointRepeater.Items.Count > 0)
{
LinkButton lb = this.endpointRepeater.Items[0].FindControl("endpointLink") as LinkButton;
this.EndpointSelected(lb, new EventArgs());
}
}
thanks,
mark
This may not be your main issue, but when including an object inside a Repeater that needs an event, you shouldn't be using that control's native events. Instead you should use the Repeater's OnCommand event.
If I were to guess, your problem is caused by the repeater not maintaining its DataBound state across PostBacks. The Linkbutton disappears from view because it is not bound to the page on every PostBack, so when the response is sent back to the client, it has nothing bound to it.
It sounds like the UpdatePanel is expecting the same (or similar) markup to be returned from the AJAX response as what is on the page already, so returning nothing for the repeater causes problems.
Try binding your repeater to the page/control in its OnInit() method. This should allow the ViewState for the repeater to be loaded on every PostBack.

Resources