I am writing a single ASP Form that dynamically changes Div boxes that are visible from mouse clicks on buttons and when text in textboxes is changed in an Ajax container. The problem i have is in the Page_Load function i create all the objects (text boxes, radio buttons, buttons, etc) dynamically from a .csv file template sitting on the asp hosting server. Everytime a postback happens, even within the Ajax window, the Page_Load function is called again and the .csv file is re-read, and all objects are re-created.
I have tried Checking for IsPostback before re-creating any objects but the objects are then nullified as they have never been created. The page is as a completely new page every single time.
Any ideas would be greatly appreciated.
Try using the Page_PreInit event rather than Page_Load to re-create/manipulate your dynamic controls:
protected void Page_PreInit(object sender, EventArgs e)
{
// create controls here
}
More info: http://msdn.microsoft.com/en-us/library/ms178472.aspx
When you create a dynamic control, you must accept the responsibility of
re-creating the control upon each postback.
You should create the control in the Page_Init event for every page
request whether it's a postback or not. If you create your controls in the Page_Init event then following that the
user entered values should automatically be filled in upon each postback so
you can acces them.
Related
This question already has answers here:
dynamically created button click event not firing
(5 answers)
Closed 8 years ago.
I have some buttons that are being dynamically added to an asp.net page. However the onclick event is not being fired. Here is the code for it being added and it is ran when the page loads. I am very new to ASP.NET so I am sure I am making some basic errors. TIA.
protected void Page_Load(object sender, EventArgs e)
{
FillTable();
string rownum = (goalstable.Rows.Count).ToString();
Button bt = new Button();
bt.Text = "View";
bt.ID = (rownum);
bt.CssClass = "button";
bt.Click += Viewbutton_Click;
goalstable.Rows[1].Cells[0].Controls.Add(bt);
}
FillTable() is a method that fills a table from an SQL DB.
The on click event for the button that has been added.
protected void Viewbutton_Click(object sender, EventArgs e)
{
getGID();
setGoalDets();
goals.Style.Add("display", "block");
darkLayer2.Style.Add("display", "block");
}
Any Ideas what I may be doing wrong.
In a nutshell, you need to add the button earlier in the Page lifecycle, before the Page_Load event.
What's happening is every server event — even simple button clicks — is a new HTTP request to your page. In turn, every HTTP request for your page results in a completely new-from-scratch C# page object. Therefore you start with a brand new Page object and a brand new ViewButton when the click event for your ViewButton is triggered.
To make things work correctly, so the new page has the same properties as the old, ASP.Net relies on a feature called ViewState. ViewState information is (typically) submitted with the http request from the client's browser, and is used to build a new Page object with the same Controls and property values as the old one.
Here's the trick: ViewState is restored for the page before the load event is processed. If the button does not exist yet at the time the ViewState is restored, that information is thrown away, and the page will not later know it needs to raise the click event (or rather, it will think there there is no button for the click event code to run in the first place).
Therefore, you need to move the code to create your button to the Pre_Init event, which runs before the ViewState is restored.
When working with "dynamic" controls in ASP.Net WebForms, I often find it easier to just add a reasonable number of controls to the page in a static manner and set them all so that their Visible property is false. Then at runtime I will set Visible back to true for just the controls that I need.
I need to add onclick event to some dynamically added button, but when i click the button, the onclick event is not fired. I saw some solutions to this, like link which says I should create the controls and attach the event on page_init or page_load every time there is a request, but, will this make the website very slow if I have a lot of controls to add?
Yes, you must recreate dynamic controls if you want to access them and have their events fire on postback.
If you have so many controls on a page that your site is slow, you have a design issue. Rethink your design so you do not have so many controls on one page (perhaps several pages/tabs?).
Allocate memory like below to button in Init Page Event
Button b = new Button();
b.Click += new EventHandler(b_Click);
void b_Click(object sender, EventArgs e)
{
}
As told by #Oded, this approach can create Design issue.
When you have a Div like control IN YOUR PAGE which is supposed to consume this Button, then you can GIVE CSS styles to give it proper alignment and proper placement.
You have two option.
Add control at Runtime
Add control at Design Time
Definitely, site will go slow in case of many controls in both cases. As both options will take memory BUT, By End of the Page Life Cycle, all the controls will get disposed.
I have an ASP.NET user control with a button, and I want to add it to the page when the user clicks a button from another user control. I have created an event handler to the first user control to handle it from the page and add the second user control to a page. Everything is working normally, but the button on the second user control doesn't respond to the event.
I place the second control on RadAjaxPanel
Note: When I add the second user control at design time its working fine.
All dynamically created controls should be added by the end of Page_Init (though sometimes you can get away with them added by the end of Page_Load).
If you're only adding them based on a button click event then you've done this in the event handers which fire AFTER Page_Init and Page_Load in the lifecycle - This is why your events don't fire and why it works fine when you add at design time.
This is because when a button is clicked on the second user control - the whole page lifecycle starts again. The page goes through Page_Load and Page_Init first and your control doesn't get loaded here. So, when the page lifecycle handles the "handle postback events" part, the control no longer actually exists, so the event doesn't fire.
Conversely, when you add at design time, the control exists in Page_Init and Page_Load so is able to handle the postback events from the user control because it already exists in the control tree - if this makes sense.
You need to think how you can restructure so they're added by the time Page_Load has finished at the very latest or it won't work. Without code samples or more detail it's hard to suggest exactly how you might do this. One possibility would be to set it visible instead of loading it outright - but if the control does some 'heavy lifting' on load like database hits or API calls then this might not be suitable for you.
I did something similar. What I did was to load some controls dynamically based on a selection from a DropDownList. If you have a method which loads the control for you, let's call it LoadControls(), then you can do something like this:
DropDownList_Click {
ViewState("LoadControls") = true;
LoadControls()
}
By setting the ViewState variable, you can then indicate Page_Load to load the controls on future postbacks:
Page_Load {
if (ViewState("LoadControls") == "true")
{
LoadControls();
}
}
This has the effect of then loading the control on-the-fly when the event first happens, and then at future times in the lifecycle.
I am dynamically generating controls, and sometimes I want to create a control and have it ignore the viewstate. For example, sometimes the user has clicked a button indicating they want a different form loaded, so the control tree I generate on postback is different from the original control tree. This is fine, except when I call Controls.Add then it tries to load the viewstate form the old controls into the new controls if the control tree structure is similar, and I want them to instead ignore that viewstate(and also ignore the postback values for input controls as well).
Can I do something like set the IDs of the controls or something that would allow me to conditionally prevent them from getting the viewstate/postback data of the previous request?
Edit: If I let the user of the control load the form on demand in postback handler, the postback data is not applied when I call Controls.Add(this really seems like a flaw in ASP.NET, because I would think if you're going to apply viewstate data "after the fact" through Controls.Add, it'd seem you would then apply the postback data automatically as well after the viewstate data is loaded). The real problem I run up against is my control is very dynamic, but the user of my control can't really tell it what to do until their postback handler fires, because one of the things a user can do is select different forms to be loaded via some link buttons. So it's not until the postback handler runs that they know what the uesr requested, and thus can ask my control to load a certain form. So I have to ask them to do convaluted things like saved the formID that identifies the last form to a session variable, and in OnInit they tell my form what the old formID was via a property. My control then loads the form in OnLoad so that it can consume the viewstate and postback data, and later in the programmer's postback handler, they can choose to clear the form and load a different one if they want.
Edit2: FYI Generating IDs for each control unique to the form works great, so I thought I could eliminate the pointless loading of the old form until the programmer requests a form be loaded in his postback handler. But as I mentioned above, what I found was that loading the form after postback data handling has occurred means that data is lost. Whereas viewstate gets loaded via Contorls.Add, playing catch up in the page lifecycle, it seems postback data does not! So it seems I am defeated at every turn.
You're going to avoid problems if you play along with the control lifetime. Basically, whenever you have a control that renders, it's best to ensure that control is recreated on the next postback, even if you aren't going to need it anymore. The first goal of a postback should be to restore the previous state -- only THEN do you make changes to it.
I described it best in this answer:
Wrong state in Server Controls with same ID's when dynamically adding UserControl to UpdatePanel
Giving the controls different ID's would certainly prevent ViewState from being loaded, that would be one way.
You may also be able to manipulate the ViewStateMode property of your controls by setting it to "Disabled". I'm not sure if this prevents it from loading (it definitely prevents them from saving viewstate), but you could try it.
Have you tried just calling controls.clear prior to adding in the new ones?
UPDATE
I'm starting to believe that you are generating the controls at the wrong point in the page lifecycle. What is your flow?
You must be generating dynamic controls on postback in pageload:
protected void Page_Load(object sender, EventArgs e)
{
--Generate Dynamic Controls--
}
You need to do it like:
protected override void OnInitComplete(EventArgs e)
{
base.OnInitComplete(e);
}
protected void OnInit()
{
--Generate Dynamic Controls--
}
protected void Page_Load(object sender, EventArgs e)
{
}
Is it possible to add instances of the same user control when an "add" button is clicked and maintain ViewState?
The user interface here is similar to the Gmail file-attachment process, where the user can click "attach another file" and another file upload box appears.
My page is surrounded by an UpdatePanel. I am able to get 1 control to load, but the button's click event fires after the Placeholder_Init method. I tried storing an integer in the ViewState that kept track of the number of user controls that should be rendered, but the Init method is also fired before the ViewState is restored.
Thanks!
Adding multiple controls dynamically is easy in ASP.NET. Let's say you have a panel named Panel declared in your ASPX file and you have a custom control called MyControl.
In your Page_Load function (or indeed pretty much anywhere), add something like the following:
for (int i = 0; i < NumberOfAttachments; i++) {
Panel.Controls.Add(new MyControl());
}
This works for UpdatePanels, too, but you'll need to call the .Update() function to get it to update on the client side if you don't have it to update on child postback.