How to prevent AutoPostBack from resetting my page? - c#

I am building a page that includes some components that are static on the page (dropdowns, buttons, a table to hold them in), but one table cell is filled with variably generated CheckBoxes. When a button is pressed, the code for the page calculates what checkboxes to place and creates a new CheckBox object for each one needed and then adds it to an existing Div on the page.
I am trying to trigger some code to run when any of these are checked or unchecked, but checkBoxName.CheckedChanged += cbCheckedChanged wasn't working. I researched and found two suggestions: enabling viewstate and enabling autopostback.
checkBoxName.EnableViewState = true; seems to make no difference, nor did checkBoxName.ViewStateMode = ViewStateMode.Enabled; or any variations on that i tried. checkBoxName.AutoPostBack = true; did SOMETHING, but it's not allowing it to run the code I want. I think that's because it doesn't reach that point because of the next problem:
With AutoPostBack = true, whenever I check or uncheck a box, cbCheckedChangedis not being executed, and the entire page is reloading, resetting back to it's initial state, therefore removing the checkboxes completely from the table.
How can I fix these problems, or at least where might I start looking?
Edit:
This is where the checkboxes are created:
CheckBox cb = new CheckBox();
cb.Text = CBName;
cb.EnableViewState = true;
cb.ViewStateMode = ViewStateMode.Enabled;
cb.AutoPostBack = true;
cb.CheckedChanged += CBCheckedChanged;
and this is where CBCheckedChanged is:
private void CBCheckedChanged(object sender, EventArgs e)
{
\\Stuff
}
When I use breakpoints to step through it, it never reaches CBCheckedChanged. I have tried every possible combination of commenting out and leaving in the AutoPostBack, ViewStateMode, and EnableViewState lines.
Page_Load is currently empty, nothing runs until the user hits a button.

ViewState is by default enabled for server side controls. You don't have to tinker around with ViewState to solve your problem. ViewState is basically used to restore the state of a control after a postback happens. For example readding all entries to a ListBox control. This is why most control population code is within such a construct in the Page_Load method.
private void Page_Load()
{
if (!Page.IsPostBack)
{
// populate controls here
}
}
ViewState is a very misunderstood concept. There is a great article here that goes into it in detail. But as I said, for your problem ViewState is not a concern.
To solve your problem:
The problem in your case is that the triggered button is creating the CheckBox controls, but when the page is reloaded, because of the CheckedChanged event of these controls, the next page life cycle has no clue of the CheckBox controls that were placed on the page in the previous page life cycle. Dynamic controls need to be generated for every page life cycle!
So what I would do is create a method that:
creates the CheckBox controls and
sets AutoPostback = true for them and
sets the event handler for CheckedChanged
Let's call this method AddDynamicCheckBoxes(). Now you need to call this method in the Page_Load event of your Page when the button was already pressed and also in the event handler of the button's click event. You could do this like follows:
private void Page_Load()
{
if (ViewState["button_was_clicked"] != null)
{
AddDynamicCheckBoxes();
}
}
private void Button_OnClick()
{
AddDynamicCheckBoxes();
ViewState["button_was_clicked"] = true;
}

Related

Determine whether the selected index was changed or an autopostback event was triggered, in sections of the code-behind other than the event handler

I have an ASP DropDownList control with the AutoPostBack property set to true. When the user changes the selection, the form posts back as expected. I want to know how to determine, in the code-behind, whether the page posted back for this specific reason.
I know that I can define an event handler like this...
protected void MyDropDownList_SelectedIndexChanged(object sender, EventArgs e) {
// Run some code if the selection for the "MyDropDownList" control was changed
}
...but what I want to know is how to check whether the form posted back because the selected index was changed outside the event handler.
Specifically, in the Page_Load() method, I have an if (IsPostback) {} section, and I want this section not to execute if the postback was caused by changing the selection in the DropDownList. So, in pseudocode, I want something like:
if (IsPostback && (! <DropDownList's selection was changed, causing an autopostback>)) {
I tried defining a global boolean variable and setting it to true in an event handler, then checking it in Page_Load(), like this:
public partial class MyWebApp : System.Web.UI.Page {
[...]
static bool selectedIndexChanged = false;
[...]
protected void DomainDropDownList_SelectedIndexChanged(object sender, EventArgs e) {
selectedIndexChanged = true; // Set this flag to true if selected index was changed
}
[...]
protected void Page_Load(object sender, EventArgs e) {
[...]
if (IsPostBack && selectedIndexChanged == false) {
[...]
}
[...]
This didn't work for a reason I presume experienced ASP.NET developers will easily spot: the event handler executes after Page_Load(), regardless of the order of the code.
I also tried to see if the control's selectedIndexChanged event can be used as a boolean condition to determine if the event triggered, like this
if (IsPostBack && !MyDropDownList.SelectedIndexChanged) {
but Visual Studio gives me the following error:
The event 'System.Web.UI.WebControls.ListControl.SelectedIndexChanged' can only appear on the left hand side of += or -="
A search on the error message led to this answer, but that doesn't seem to help because it relies on the event handler, which executes after Page_Load().
In my particular use case, where there is only one DropDownList and only one other way to submit the form (the submit button), it would be equally effective to check whether the selected index was changed, whether an AutoPostBack was triggered, or whether the submit button was clicked, but I'd also like to know how to do this in a broader range of scenarios, for example if there are multiple AutoPostBack controls and/or multiple ways to submit the form other than AutoPostBack.
So, my question breaks down as follows (though some of these may be essentially the same question, depending on what the answer is):
Is there a way to determine in general whether an AutoPostBack was triggered, as opposed to the form posting back for any other reason, such as clicking a button?
Is there a way to determine if a specific control's AutoPostBack was triggered (i.e. if there are multiple controls with AutoPostBack true, can it be determined which control caused the AutoPostBack)?
Is it possible to check in the Page_Load() method or any other code that executes before the SelectedIndexChanged event handler whether a DropDownList's selected index was changed?
If there's a better way to achieve what I'm trying to accomplish in this particular case, I'm open to suggestions, but I'd still like to know the answer(s) to the above.
During Page_Load inspect Page.Request.Form["__EVENTTARGET"]. This will contain an identifier representing the control that caused the post back. From this you should be able to determine whether the post back was caused by the control you're interested in.
if (IsPostBack && Request.Form["__EVENTTARGET"] != "<control ID>") {
...
}
Is it possible to check in the Page_Load() method or any other code that executes before the SelectedIndexChanged event handler whether a DropDownList's selected index was changed?
Not without resorting to a custom technique. The SelectedIndexChanged event fires too late during the page event lifecycle to be useful to your scenario. One option is to store the DropDownList.SelectedIndex into the Page.ViewState collection during Page.OnPreRender and then comparing this value to the new DropDownList.SelectedIndex on the post back during Page_Load.

Dynamically add Button to Panel

I am adding a RadButton dynamically to a Panel. So I am creating the button as so:
RadButton btnAwesome = new RadButton();
btnAwesome.AutoPostBack = true;
btnAwesome.Text = "Click me...";
btnAwesome.ID = "LinkButtonTest";
btnAwesome.Click += new System.EventHandler(lnkbtnEditRecord_Click);
and it it should call this method onclick:
protected void lnkbtnEditRecord_Click(object sender, EventArgs e)
{
salesEditPanel.Visible = true;
resultPanel.Visible = false;
zipPanel.Visible = false;
ddlPanel.Visible = false;
topPanel.Visible = false;
}
It adds the button the Panel but it doesn't add the onclick to it. Any idea what I am missing?
Thanks!
You will need to run that code to initialize the button on every postback, and you will need to ensure that it's run sufficiently early in the page's lifecycle. Which page event is that code in, and will it be run on each successive postback?
The issue here is due to how postbacks work - Each time a page is requested (postback or not), the control instances are created. Once the controls are created and other page properties set, the viewstate is parsed to set the control's properties. Then events are created and dispatched.
The important thing here is, this instance of "page" is not the same instance that you generated before - it's a new one and the ASP.NET webforms engine has set all the properties for you as if it were the same. But on this instance, you haven't created your btnAwesome, so there's nothing there to send a "click event" from or to!
In order to change this, you need to make sure that by the end of Page_Load, all of the controls you want to fire events have been created. So you must recreate btnAwesome and add it to the panel before returning from Page_Load if you want it to fire the click event.

adding an event handler to a dynamically created checkbox (aspx, c#)

So my problem is that I want to add an event handler to a dynamically created CheckBox. I have already looked at other ways to do this, and decided that creating a dynamic table which contains my CheckBoxes is the best option for me. I have not added these CheckBoxes to the Control Tree because I need to manage the ViewState manually. Either way, my code works in every way except that my CheckBox's CheckChanged Event does not fire. I am adding this eventhandler to my CheckBox in my pageLoad event, however, any page event I try seems to give me the same results:
CheckBox chbxLv1 = new CheckBox();
chbxLv1.ID = "DymanicallyCreatedIDForIdentification";
chbxLv1.AutoPostBack = true;
chbxLv1.CheckedChanged += new EventHandler(this.checkChanged);
/* Way lower in my code */
protected void checkChanged(object sender, EventArgs e)
{
//Some code goes here which never seems to execute... grrr
}
I thought that this may be a problem with the ViewState at first and did quite a bit of research on that. I'm now thinking I am doing something dumb with adding an event handler. I'm not sure why this event never fires, but I'm a little new at adding events to a control. Do I need a delegate here?
--Roman
In order for dynamically loaded controls to be handled properly during the ASP.NET Page Lifecycle, they need to be added to the page during OnInit (or prior to LoadViewState, really) otherwise their state information will not be maintained and you can, in fact, corrupt the viewstate depending on how/where things are added in the page's control graph.

When I add an custom UserControl to a Panel dynamically, the usercontrol loses all event handling

I've got aspx page which dynamically loads UserControl into a Panel object based on the input on a set of radio buttons. The UserControl successfully adds and displays properly to the Panel on postback and calls the Page_Load() event just fine in the UC but when I interact with the form in any way that would trigger an event, the event is not captured on the postback.
I've tried to add the event handling association in the Page_Load() which I know gets called as well as adding the association in the ASP.NET tag without any difference in result.
This is how I am adding the control (object names have been simplified):
private UserControl _control;
protected void RadioButtonGroup_CheckedChanged(object sender, EventArgs e)
{
RadioButton radioButton = (RadioButton)sender;
if (radioButton == RadioButton1Ctl)
{
_control = (UserControl1)LoadControl("~/Controls/UserControl1.ascx");
PanelCtl.Controls.Add(_control);
}
else if (radioButton == RadioButton2Ctl)
{
_control = (UserControl2)LoadControl("~/Controls/UserControl2.ascx");
PanelCtl.Controls.Add(_control);
}
}
As I said, the control gets successfully added by when I click any buttons or have any postback events which should be bound on the UC, the control gets removed from the page and events aren't fired.
Any help would be greatly appreciated.
This is happening because the controls are being added dynamically. I would suggest using the DynamicControlsPlaceHolder instead of a Panel. It will persist your controls for you when the page is posted back.
DynamicControlsPlaceHolder:
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
The other alternative is to recreate the controls at every postback, before the ViewState is reloaded. I would suggest using OnInit.
The DynamicControlsPlaceHolder takes all of the hard work away, so that might be the best option for you.

Cannot get values in OnInit event

I understand the order the events occur with page life cycle but it is not helping with my situation. I have a checkboxlist that is populated by a directory filled with forms. When I check a box next to the name of the form I would like it to dynamically create a wizard step and insert the form.
Order of events:
OnInit:
GatherForms() - Checks directory and loads all form names into checkbox
LoadForms() - Checks "Selected" Session and loads forms that were collected
CheckBoxList:SelectedIndexChanged #AutoPost = true#
PopulateForms() - Loops through the checkboxs and adds them to session state
When the user clicks the checkbox it does a postback and hits the OnInit which pulls from the session. The problem is that PopulateForms() was not ran yet so it populated nothing even though it is checked. If I click another item it will postback and appear. I cannot seem to be able to pull any kind of useful information from the checkbox before the refresh which means I cannot see the forms appear immediately. I have also tried looping the checkbox but unfortunately viewstate hasnt posted yet. sigh.
Any suggestions?
Thanks!
P.S: I cannot use Request.Form[] because I have to get all the selected items out of the checkbox. maybe i can but i cannot find a way :/
This is a common problem I wrestle with as I get better at ASP.NET.
With dynamic controls you have the problem of them not actually existing during OnInit.
What you can do is create all of the controls the user may see during OnInit, and hide the elements the user won't see in code. The page will load, all possible controls will be instantiated (in code - don't worry this appearing in your HTML and bloating it), then the event handler will fire, and then you can deal with setting the visibility of your wizard.
For example:
public void OnInit(object sender, EventArgs e)
{
GatherForms();
CreateWizardForm(); // creates a wizard and adds controls it will need
}
private void Checkbox_Checked(object sender, EventArgs e)
{
var checkBox = (CheckBox)sender;
// append checkBox.SelectedValue to session state object of checkboxes
}
protected override void OnPreRender(object sender, EventArgs e)
{
if (/* Session checkboxes contain values */)
{
this.WizardForm.Visible = true;
this.CheckboxList.Visible = false;
}
}
This works provided you know ahead of time which controls will be in the wizard form. You can change the values of those controls in the OnPreRender event, toggle their visibility, etc, but you can't go and add new controls (e.g. Controls.Add(new Button())) - that has to be done in the OnInit event.
Only add your dynamic controls in OnInit. Don't do any population/processing until PageLoad. You will retain your values this way.
A classic pitfall with dynamic controls.
Honestly the best solution is to just wield the Request values array to look for the information you need and ignore the lifecycle stuff for this particular situation.
In OnInit(), the posted values are there, they just haven't been dealt with by ViewState yet. So you can just do if (Request["myCheckBoxName"] == xxx) to deal with individual checkboxes, or if you can use Request["__EVENTTARGET"] to get the name of the control that caused the postback.
See my old answer here for a more thorough discussion of the issue.

Categories

Resources