I've a asp:TextBox and a submit button on my asp.net page. Once the button was clicked, the TextBos's value is posted back. I'm going to keep the the posted-back text value into session, so that other child controls can access to the value during their Page_Load. However, I always get NOTHING ("") in the Page_Load method, and I can read the text out in the button click handler. I know that the "button click event" happens after the Page_Load. So, I'm asking how can I "pre-fetch" the TextBox.text during Page_Load?
public partial class form_staffinfo : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e){
string s = staff_id.Text; //Reach this line first, but GET empty value. However, I want to keep it in the session during this moment.
}
protected void btn_submit_Click(object sender, EventArgs e) {
string s = staff_id.Text; //Reach this line afterward, value got.
}
}
-- EDITED --
<%# Control Language="C#" AutoEventWireup="true" CodeFile="form_staffinfo.ascx.cs" Inherits="form_staffinfo" %>
<asp:Label ID="Label1" runat="server" Text="Staff ID: "></asp:Label>
<asp:TextBox ID="staff_id" runat="server" ></asp:TextBox>
<asp:Button ID="btn_submit" runat="server" Text="Query" OnClick="btn_submit_Click" />
Since I can't get the TextBox's text in the Page_Load, so, I didn't include any code related to session for clear presentation.
Thank you!
William
None of the values of your server controls are available for consumption in the Page_Load. Those controls are assigned after the form is validated (which is after the form is loaded) and before the form's control's events fire (like button clicks, in your example). The values posted are in the Request.Form Collection. Look in the AllKeys property and you should see a key that ends in $staff_id if you use your example posted. There may be other characters in from of the key, depending upon if the control is nested in a master page or other control.
If you absolutely must have that value at page load, grab it from the Request.Form collection instead of the user control, but I would question the wisdom of capturing the value that early in the page lifecycle. You could conceivably capture the textbox's OnTextChanged Event if you needed to preserve the value in Session.
EDIT - Additional Explanation
if you were going to create a custom event for your user control, there are only a couple of steps to it.
Create a delegate. This is will be the common object for inter-control messaging.
public delegate void StaffIdChangedEvent(object sender, string staffId);
Declare an event using that delegate in the user control that is going to broadcast.
public event StaffIdChangedEvent StaffIdChanged;
In your user control, when you are ready to broadcast (say from the Staff_id textbox's OnTextChanged event), you just invoke the event [Its generally a best practice to check to see if the event is null]
this.StaffIdChangedEvent(this, "staff-id-value-here");
The final step is to wire the user control event up to an event handler (this prevents the null situation I mentioned above when trying to invoke the event). You could wire a handler into the hosting page.
this.form_staffinfo.StaffIdChangedEvent += this.some_method_on_page;
Just make sure the method on the page has the same method signature as the delegate used to declare the event.
Events also could be wired into each control that needs to know about them (look up multicast delegates), so you could do something like:
this.form_staffinfo.StaffIdChangedEvent += this.some_method_on_page;
this.form_staffinfo.StaffIdChangedEvent += this.some_control_on_the_page;
this.form_staffinfo.StaffIdChangedEvent += this.some_other_control_on_the_page;
In any event, I generally preferred to do this type of wiring in the page's OnInit method.
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
InitializeComponent();
}
and just write your own InitializeComponent method to centralize any of this wiring you have to do.
There is something else that is setting the textbox value. Could you please check if you are overriding other event that occurs before Page_Load and modifying the textbox text property. Even, posting the code where you update session variable would be handy. From the code you have posted, it should work.
Do you have autoeventwireup disabled? I could be mistaken, but I think if it is disabled your Page_Load will not fire. If you want to leave it disabled, you can always override the OnLoad event...
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// do stuff
}
Related
Disclaimer: I have read the ASP.net page life cycle, and I've also read several good articles pertaining to dynamic controls, but I must be missing something.
Background: I am currently working on a website which needs to create a lot of dynamic content based on the user's input. I understand that, in order for dynamic controls to persist and for their events to wire up correctly, I need to re-create those dynamic controls on every page post-back.
Because of the nature of my project, my code doesn't know WHAT controls to create unless it has some information about what the user selected. I'm storing the user's choices in the ViewState, which is unavailable in Page_Init because it has not yet loaded. Consequently, I have to wait until Page_PreLoad or Page_Load to read the ViewState and then re-create my dynamic controls.
The part I don't understand: When I try re-creating my controls during Page_Load, the controls persist but the associated events don't seem to fire. For example, clicking on a LinkButton I created does not fire the method that I wired to its Click event, even though the button itself does persist.
A strange solution that I discovered by accident is that I can instead re-create my controls during Page_PreLoad and then the events fire correctly.
My question (or questions, rather): Why does my problem appear to go away by re-creating my controls during Page_PreLoad instead of Page_Load? Is this a safe practice? I've never seen any other code that used Page_PreLoad, which makes me wary. This solution is working for me, but are there any pitfalls I might be missing? Am I unknowingly setting myself up for failure later on?
My code, where LoadDocument() is a method that creates controls and stuffs them into a static Panel control:
protected void Page_PreLoad(object sender, EventArgs e)
{
if (ViewState["xmlfilename"] != null)
{
LoadDocument(ViewState["xmlfilename"].ToString());
}
}
Your events are processed during the ProcessPostData. Which control triggered the postback, too is post data. If your control does not exist at that time, it will not receive the event.
I agree Init would be too early, and Load too late.
What you need to do here is create these controls as soon as your view state is loaded.
There is no event for this in the Page life cycle. However all the functions being virtual, you can override the functions called in between.
The best place to load such controls that depend on values stored in the ViewState is the LoadViewState function.
Override this function.
Remember to call base.LoadViewState at the very start.
Create your controls depending on the ViewState values.
Now all your controls events should fire properly.
Probably you read one of my answers on this topic:
https://stackoverflow.com/a/11127064/1268570
https://stackoverflow.com/a/11061945/1268570
https://stackoverflow.com/a/11167765/1268570
I can tell you that I have code on production using the PreLoad event and it has worked fine
But for new development I am using the Init event, Why? Because it is the Microsoft recommendation and therefore it can be considered as an standard, and the technical benefits such the automatic load of the ViewState, theme support, and the most important (from my point of view), the dynamic controls events are sync with the static controls.
Your concern is right, in the Init event the ViewState has not been loaded yet, but that doesn't stop you to access the Form collection
I created a page for learning purpose where I'm creating dynamic controls on demand, and I'm doing it in the Init event. I'm creating TextBoxes and on each post they raise their TextChanged event when the text is changed.
NOTE: before continue I would like to remind you that the ViewState is loaded matching the control's ID's, that's why it's a good practice to re-create always the dynamic controls using the same ID
This is the code:
ASPX
<asp:HiddenField runat="server" ID="numberOfDynamicControls" Value="0" />
<asp:Panel runat="server" ID="myPanel">
</asp:Panel>
<asp:Button Text="Add Control" runat="server" ID="addControl" OnClick="addControl_Click" />
<asp:Label ID="lblMessage" runat="server" />
ASPX code behind
protected void Page_Init(object sender, EventArgs e)
{
this.CreateDynamicControls();
}
protected void addControl_Click(object sender, EventArgs e)
{
var n = int.Parse(this.numberOfDynamicControls.Value);
n++;
this.numberOfDynamicControls.Value = n.ToString();
this.myPanel.Controls.Add(this.CreateTextbox(n));
}
private void CreateDynamicControls()
{
int n = 0;
if (!string.IsNullOrWhiteSpace(this.Request.Form["numberOfDynamicControls"]))
{
n = int.Parse(this.Request.Form["numberOfDynamicControls"]);
}
for (int i = 0; i < n; i++)
{
var t = this.CreateTextbox(i + 1);
t.TextChanged += (x, y) => this.lblMessage.Text += "<br/>" + (x as TextBox).ID + " " + (x as TextBox).Text;
this.myPanel.Controls.Add(t);
}
}
private TextBox CreateTextbox(int index)
{
var t = new TextBox { ID = "myTextbox" + index.ToString(), Text = "de" };
return t;
}
I'm aware this question has been asked many times before but I suspect I have a unique scenario.
I'm loading a Child Control (ASCX) and setting a Property on that Control. This works perfectly fine until postback where the property is null.
Herewith the First Class which loads the ChildControl :
protected override void CreateChildControls()
{
MyUserControl control = (MyUserControl)Page.LoadControl(_ascxPath);
control.MyProperty = base.MyProperty
Controls.Add(control);
}
Then, on my Child Control I've got the following code:
public partial class MyUserControl : UserControl
{
public MyType MyProperty { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Exception on next line because Property is null (only on postback)
var somevalue = MyProperty.SubProperty;
Ok. Let me try to explain it.
1. Once page is created, you get full page lifecycle
2. You click on some control to create user control, and you get it
3. Now you are entering value to this control, and getting postback
4. On server side postback is handled, but as you can see viewstate actions appear as soon as page is loaded.
One of main purposes of viewstate is handling control events, to see if they are changed, or save their states or something else.
5. If on the moment, when viewstate is loaded you control is still not constructed, then all it's events and values would be ignored.
Solution either make it static control and just hide it, either create it before viewstate actions started.
You need to add the control and set properties in the Page_Init event, other wise you will lose the properties value.
In Microsoft explanations about ASP.NET page life cycle, it is written that dynamically created controls must be created in PreInit.
It worked for me.
Here is my main page :
protected global::System.Web.UI.HtmlControls.HtmlGenericControl FiltersZone;
(. . .)
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
FiltersZone.Controls.Add(new PlanningFiltersSurgeonWeb());
}
This dynamically created ".ascx" control contains an hidden field :
<input id="hidTxtPaint" type="hidden" name="hidTxtPaint" runat="server" />
I am now able to retrieve its value from within dynamically created ASCX control Page_Load event, after a "submit" or a "__dopostback('hidTxtPaint')" initiated from JavaScript.
On the other hand, the hidden field's value is always empty after a POST if its parent ".ascx" control is added in main page's Page_Load event.
I'm having problems with event handlers always firing on HiddenFields despite no changes to the field that I'm aware of.
I have an ASCX user control where I statically declare some elements:
MyControl.ascx:
<div id="AnItem" runat="server">
<asp:Textbox id="TextBox1" runat="server" />
<asp:HiddenField id="HiddenField1" runat="server" />
</div>
(There's obviously a lot more there, but this is the markup of note)
MyControl.ascx.cs:
protected override void OnInit(EventArgs e){
base.OnInit(e);
if (SelectedValue != null){
TextBox1.Text = SelectedValue.Text;
HiddenField1.Value = SelectedValue.ID.ToString();
}
}
protected override void OnLoad(EventArgs e){
base.OnLoad(e);
if (String.IsNullOrEmpty(TextBox1.Text))
TextBox1.Attributes["style"] = "display:none";
TextBox1.TextChanged += ItemTouched;
HiddenField1.ValueChanged += ItemTouched;
}
protected void ItemTouched(object sender, EventArgs e){
// process changed values
}
The code seems unconventional because I've omitted items unrelated (I assume) to my question.
My control is actually created dynamically using a wrapper class that I can serialize:
[Serializable]
public class ListControl{
public void GenerateControl(TemplateControl parent){
var control = parent.LoadControl("~/MyControl.ascx") as MyControl;
control.Options = _options;
control.SelectedValue = _selectedValue;
return control;
}
private IList<SelectableOption> _options;
private SelectionOption _selectedValue;
}
(The reasons for this wrapper are due to a large legacy code base that is too slow in creating the list of selectable values. The _options list is generated once and then kept in the session to speed up postback execution.)
ItemTouched is attached to every element that may be touched by the user (or manipulated by JavaScript). My problem is that it's being fired on every postback - even when HiddenField1 wasn't modified on the client side (I've confirmed this by removing all JavaScript that touched it).
I'm at a loss as to why the handler is being fired is the value isn't being touched. It does not fire when the control values aren't set (e.g. in my OnInit method), but always does if they are "pre-set". I don't expect the change handlers to fire if I attach the event handlers after setting the default values, but this doesn't seem to be the case. Am I making a fundamentally bad assumptions about ASP.NET events?
It's been a while, but if I recall correctly HiddenField or Textbox controls fire ValueChanged based on comparing their current value with the value stored in ViewState. Since you're dynamically creating these controls, I'm guessing their viewstate isn't getting rehydrated properly (or early enough) - which then triggers the ValueChanged event handler to fire (since they have a value that differs from that stored in ViewState).
Your best shot at really understanding what's going on is to enable debugging on the .NET Framework: http://msdn.microsoft.com/en-us/library/cc667410.aspx and set some breakpoints around the area where ValueChanged is fired. Then you can see what condition is causing it, and that should hopefully help you figure out how to work around it.
Is it possible to stop an ItemCommand or control event from bubbling up the control hierarchy? I have a control that contains child user controls that may or may not already have code that handles their ItemCommand events. What I would like to do is to allow the child control to decide to not pass the ItemCommand along to the parent control in the event it already processes the event in its code-behind.
Thanks,
Mike
In your user control class, override OnBubbleEvent(). If you return true, you will stop the "bubble up" to the parent controls.
protected override bool OnBubbleEvent(object source, EventArgs args)
{
//handled
return true;
//uncomment line below to bubble up (unhandled)
//return base.OnBubbleEvent(source, args);
}
Another somewhat neat thing to think about that I found while tinkering on this, which might be useful in some instances... you can change the command name that 'bubbles up' in the control heirachy as well. In your child user control, use OnCommand, rather than Onclick.
So, say you have a button in your user control, change the code from this:
<asp:button id="mySpecialButton"
onClick="mySpecialButton_OnClick" runat="server">
to this:
<asp:Button id="mySpecialButton"
CommandName="mySpecialCommand"
CommandArgument="myArgument"
OnCommand="mySpecialButton_Command"
runat="server"/>
then in the codebehind,
protected void mySpecialButton_Command(object sender, CommandEventArgs e)
{
RaiseBubbleEvent(this, new CommandEventArgs("Handled", e));
}
Thus, in your parent control's ItemCommand handler you will then get this new command name rather than the original command name from the child control, which you can do with as you see fit.
The Click event technically is not bubbling. That event is raised and handled by your code but the list control is also watching the Click event and raising an ItemCommand event. There's no way to prevent that because you can't even guarantee which event handler will be called first.
Do you have a CommandName associated with the button that you don't want raising that event? You should probably get rid of your Button_Click event entirely and do your command handling in the ItemCommand event, checking the event args for the CommandName and reacting appropriately.
In other words, use a CommandName that identifies what you want to happen, then in the ItemCommand event, only take action when you see a CommandName that you are responsible for handling.
Set e.Handled = true (if e is the name of your event).
I'm trying to create a custom server control (WebControl) with a text box.
I add asp.net textbox to the custom control in CreateChildControls override. In OnInit override I add event handler to TextBox.TextChanged.
Everything works, except that TextChanged never fires. I looked at viewstate and it looks like my textbox never saves its Text property in the viewstate. I've tried to set Text in various places, including constructor, but nothing works.
How can I get TextBox dynamically added to WebControl to save it's Text in viewstate and get TextChanged event to fire?
I would greatly appreciate an example of WebControl code behind with TextBox being added dynamically and TextChanged event being fired.
The dynamically created control must be created again in each post back, (the pageInit event is the better option) for the event to be fired.
BTW, if you want the TextChanged event to generate a postback you must also set the AutoPostback of the control to true.
fixed it. dynamic control must be created and added in Init event. It must be assigned an ID without special ASP.NET symbols ('$' or ':' inside custom ID will break things). All properties must be assigned after control is added to the controls tree.
here's a working example for Page codebehind:
private readonly TextBox _textBoxTest = new TextBox();
protected void Page_Init( object sender, EventArgs e )
{
this.form1.Controls.Add( _textBoxTest );
_textBoxTest.Text = "TestBoxTest";
_textBoxTest.ID = "TestBoxTestId";
_textBoxTest.TextChanged += this._textBoxTest_TextChanged;
}
void _textBoxTest_TextChanged( object sender, EventArgs e )
{
_textBoxTest.Text = "Worked";
}
for WebControl place init code in OnInit override
This will help you out. In short, you need to handle the viewstate for your Dynamically added control on your own.