Why aren't all controls initialised at the event handling point of the ASP.NET page lifecycle? - asp.net

I have a user control embedded in a web part. It has the following snippets of code:
protected TextBox searchTextBox;
protected Button goButton;
protected Button nextButton;
protected Repeater pushpins;
protected Label currentPageLabel;
protected void goButton_Click(object sender, EventArgs e)
{
// Do stuff
}
<asp:TextBox ID="searchTextBox" runat="server" />
<asp:Button ID="goButton" runat="server" Text="Go" OnClick="goButton_Click" />
<asp:Repeater ID="pushpins" runat="server" EnableViewState="false">
<ItemTemplate>Blah</ItemTemplate>
</asp:Repeater>
<asp:Label ID="currentPageLabel" runat="server" />
<asp:Button ID="nextButton" runat="server" Text=" >> " OnClick="nextButton_Click" />
(There is no OnLoad or CreateChildControls method.)
If I place a breakpoint on the first line of goButton_Click, I find:
searchTextBox: initialised
goButton: initialised
nextButton: NULL
pushpins: initialised
currentPageLabel: NULL
Why are some controls initialised and others not? How do I get around this if I'd like to update the Text property on currentPageLabel?
Update:
I've placed breakpoints all the way through the page life cycle and found that nextButton and currentPageLabel are never initialised. The breakpoints were placed at OnLoad, CreateChildControls, goButton_Click, OnPreRender, Render and OnUnload.

Is it possible you've inadvertently got local variables named currentPageLabel and/or nextButton declared somewhere? The compiler will happily allow this...
This is especially common in a move from ASP.NET 1.1 to 2.0 or higher, since the way the designer defined these controls changed.

The problem was that all of the controls that weren't being initialised were inside a HeaderTemplate within a Repeater control. (To save space I didn't paste all of my code into the question, dang it.)
I moved them out and the problem is resolved. Obviously controls in the HeaderTemplate are instantiated by the Repeater and do not follow the normal page life cycle.

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

Unable to update label in update panel from user control ASP.net

My code is as follows.
<div class="table">
<asp:UpdatePanel runat="server" ID="labelPanel" UpdateMode="Conditional" >
<ContentTemplate>
<asp:Label Text="" runat="server" ID="Cost"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
<uc1:ucPartsListing ID="ucPartsListing" runat="server" />
</div>
Now the usercontrol ucPartsListing itself has 2 update panels. There is an event fired from the user control to parent aspx for some conditions.
In that event, I am trying to set the label value which is present in aspx file. I am calling update manually from code-behind. Yet it doesn't work. Where am I going wrong ?
public partial class PartsEnquiry : BaseAuthPage
{
protected void Page_Load(object sender, EventArgs e)
{
ucPartsListing.OnQuotePartsItemSelect += new ascx.ucPartsListing.QuotePartsItemEventHandler(ucPartsListing_OnQuotePartsItemSelect);
}
void ucPartsListing_OnQuotePartsItemSelect(string price)
{
Cost.Text = price; //This is not working !
labelPanel.Update();
}
Set a breakpoint on your "void ucPartsListing_OnQuotePartsItemSelect(string price)" method and see if it gets hit at all.
I'm not sure what the user control is that you are using, but whatever control it is that is supposed to fire the event, try setting its AutoPostBack property to True.
I think you are out of luck with your current structure.
When the UpdatePanel inside you user control is fired in the browser, it will update the part of the page that is inside itself. You cannot update controls that are outside of the executing UpdatePanel.
Manually calling the Update() method on the outer UpdatePanel will not help since on the client it is still one of the inner UpdatePanels that is receiving the output back and updating the html tree.
To get it to work you will have to somehow trigger the outer UpdatePanel which will be able to update the Cost label.

asp.net set textbox control in panel contol

I want to set the textbox contol located in the panel control via code
I know to retrieve the inputted value in the textbox control:
string myVal = Request.Form["txtResult"];
I want to set the txtResult.text = "some text";
makeup snippet:
<asp:Panel ID="Panel1" runat="server" Style="display: none" Width="233px">
<asp:TextBox ID="txtResult" runat="server" AutoPostBack="True"></asp:TextBox>
<br />
<div align="center">
<asp:Button ID="OkButton" runat="server" Text="OK" />
<asp:Button ID="CancelButton" runat="server" Text="Cancel" />
</div>
</asp:Panel>
txtResult is not available within code, I tried to see if it is available in the page_load, it's not
texReults was a typo, its txtResult, I updated the ID
the intellisense does not recognize any cntr by the name txtResult
its a new web application and the panel visibility=True
maybee this wil help, above the snipet, I use ScriptManager from the AJAX Exstension
I am aware of he Asnchronius affects, partial potback, etc.
It's a managed control, you should be able to set it on the Page_Load event:
protected void Page_Load(object sender, System.EventArgs e)
{
txtResult.Text = "some text";
}
Update: Based on your update, there are a couple of things that you would need to check:
Spelling: Are you sure you're spelling the control name correctly?
Its ID in your code is "txtResults", but you're referencing it as
"txtResult".
Designer: Did you copy the aspx page or bypass VS in some way for this page? If so check the .designer file for the reference to the control: i.e. "Page1.aspx.designer.cs"
Visibility: Is the Panel control's visibility set to true? If not, then it won't render the controls that are contained within it.
Update 2: If you're doing this through scriptmanager, then I highly recommend that you read through this: http://www.wrox.com/WileyCDA/Section/Using-the-ASP-NET-AJAX-ScriptManager.id-305492.html

DropDownList's SelectedIndexChanged event not firing

I have a DropDownList object in my web page. When I click on it and select a different value, nothing happens, even though I have a function wired up to the SelectedIndexChanged event.
First, the actual object's HTML code:
<asp:DropDownList ID="logList" runat="server"
onselectedindexchanged="itemSelected">
</asp:DropDownList>
And this is that function, itemSelected:
protected void itemSelected(object sender, EventArgs e)
{
Response.Write("Getting clicked; " + sender.GetType().ToString());
FileInfo selectedfile;
Response.Write("<script>alert('Hello')</script>");
foreach (FileInfo file in logs)
{
if (file.Name == logList.Items[logList.SelectedIndex].Text)
{
Response.Write("<script>alert('Hello')</script>");
}
}
}
None of the Responses appear, and that portion of JavaScript is never run. I've tried this on the latest 3.6 version of Firefox, as well as Internet Explorer 8. This is being served from a Windows Server 2003 R2 machine, running ASP.NET with the .NET Framework version 4.
Set DropDownList AutoPostBack property to true.
Eg:
<asp:DropDownList ID="logList" runat="server" AutoPostBack="True"
onselectedindexchanged="itemSelected">
</asp:DropDownList>
try setting AutoPostBack="True" on the DropDownList.
I know its bit older post, but still i would like to add up something to the answers above.
There might be some situation where in, the "value" of more than one items in the dropdown list is duplicated/same. So, make sure that you have no repeated values in the list items to trigger this "onselectedindexchanged" event
Add property ViewStateMode="Enabled" and EnableViewState="true"
And AutoPostBack="true" in drop DropDownList
Also make sure the page is valid.
You can check this in the browsers developer tools (F12)
In the Console tab select the correct Target/Frame and check for the [Page_IsValid] property
If the page is not valid the form will not submit and therefore not fire the event.
For me answer was aspx page attribute, i added Async="true" to page attributes and this solved my problem.
<%# Page Language="C#" MasterPageFile="~/MasterPage/Reports.Master".....
AutoEventWireup="true" Async="true" %>
This is the structure of my update panel
<div>
<asp:UpdatePanel ID="updt" runat="server">
<ContentTemplate>
<asp:DropDownList ID="id" runat="server" AutoPostBack="true" onselectedindexchanged="your server side function" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
Instead of what you have written, you can write it directly in the SelectedIndexChanged event of the dropdownlist control, e.g.
protected void ddlleavetype_SelectedIndexChanged(object sender, EventArgs e)
{
//code goes here
}

FileUpload in FormView inside an UpdatePanel

The Scenario:
I have an ASP.Net webpage which I intend to use for letting the user(not the real users, but content manager basically) insert and edit the records in a table using a FormView. This FormView is inside an UpdatePanel, as I'm also using cascading dropdownlists to let the user select some values.
Now, this FormView also contains 4 FileUpload controls, and as you might know that these fileupload controls require a full postback since most browsers do not let Javascript access the disk. So, this problem would have been solved by doing something like:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="InsertButton" />
<asp:PostBackTrigger ControlID="UpdateButton" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>
Edit: Forgot to add that the fileuploading takes place in the OnUpdating and OnInserting events of the SqlDataSource.
The Problem:
Since the InsertButton and the UpdateButton reside inside the Formview, I cannot directly access their ID's through markup. And MSDN says that:
Programmatically adding
PostBackTrigger controls is not
supported.
Please suggest some solution to make this work. Any insight on the matter is highly appreciated. Thanks.
P.S.- A workable solution for me was to set the UpdatePanel's PostBackTrigger as the whole FormView itself:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="FormView1" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>
But now due to a bit of change in requirements, this solution(if you call it a solution) is not acceptable.
Have you given a though about using Iframe for doing the postback ? something like:
<iframe name="uploader" id=uploader
src="uploaderSender.aspx?AllowedExtension=<%= AllowedExtension %>&StoringPath=<%= StoringPath %>&StoringFileName=<%= StoringFileName %>&OldFileName=<%= OldFileName %>&MaximumSize=<%= MaximumSize %>"
width="450" height="50" frameborder=0 scrolling=no >
</iframe>
with uploaderSender.aspx like :
<form action="UploaderReceiver.aspx" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" onchange="document.getElementById('IsFileUploading').style.visibility = 'visible'; document.forms[0].submit()"/>
<span id="IsFileUploading" style="visibility: hidden">
<asp:Image ID="Image1" runat="server" ImageUrl="~/immagini/Ajax-loader.gif" />
</span>
</form>
and UploaderReceiver.aspx like :
protected void Page_Load(object sender, EventArgs e)
{
//if there is one file to process
if (Request.Files.Count > 0)
//create the folder if it does'nt exists and returns the local path to get it
string StoringPathToBeSaved = StoringPath.GetFolderPath();
// append the name of the file to upload to the path.
StoringPathToBeSaved = StoringPathToBeSaved + StoringFileName + Extension;
Request.Files[0].SaveAs(StoringPathToBeSaved);
}
this is just bits of code just for you to figure out if you would be interested in this way of dealing with the upload, I can give you more if you want after.
see you, and good luck with your code,
Yay!! Finally got it to work!
Here's How:
Well contrary to what MSDN says, we can in fact add PostBack Triggers Programmatically. Not necessarily to the UpdatePanel, but to the ScriptManager.
After hours of playing around, here's what worked:
We are not able to access controls inside a FormView, untill the template has been rendered, so we can only add postback triggers after the formview's OnDataBound Event.
protected void FormView1_DataBound(object sender, EventArgs e)
{
if (FormView1.CurrentMode == FormViewMode.Edit)
{
LinkButton lb = (LinkButton)FormView1.FindControl("UpdateButton");
ScriptManager.GetCurrent(Page).RegisterPostBackControl(lb);
}
//Similarily you can put register the Insert LinkButton as well.
}
And now, if your UpdatePanel causes ConditionalUpdate, you can do something like this to make it work:
The Markup:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>..
<EditItemTemplate>
...
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" OnClick="Cause_PostBack"CommandName="Update">Update</asp:LinkButton>
...
</EditItemTemplate>
..</ContentTemplate>
</asp:UpdatePanel>
CodeBehind:
//call this function as the OnClick Event Handler for the Controls you want to register as
//triggers.
protected void Cause_PostBack()
{
UpdatePanel1.Update();
}
Otherwise, if your situation allows it(as mine does), just set the UpdatePanel's UpdateMode="Always"
This is old, but was trying to solve another problem and ran into this. This wasn't my problem, but here's an alternative for anyone new who runs into this as well.
You stated your problem as:
Since the InsertButton and the UpdateButton reside inside the Formview, I cannot directly access their ID's through markup
You actually can access their ID's through markup to use as the ControlID in the PostBackTrigger. You just have to use the button's name that is created in the page html mark-up as the ControlID. You can find the name created by viewing the page source when you're viewing the page in the browser. It typically is the name of the FormView + $ + name of the button.
For example, let's say you have a FormView named "FormView1" that contains an Insert button which you gave the ID of "btnInsert" during design. If you open up your page in the browser to view it live and then view the page's source, you'll notice that the html mark-up of the button will actually be given the name "FormView1$btnInsert".
Use that name as the ControlID in your PostBackTrigger and your update panel will work.
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="FormView1$btnInsert" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>

Resources