I'm building an ASP.NET application. I'm using a ListView to show some Entities however my listview doesn't have items on the first pass. I mean, they show up on the page, but this code only works when I refresh the page:
protected void Page_Load(object sender, EventArgs e)
{
fillFeatures();
}
private void fillFeatures()
{
using (Entities myEntities = new Entities())
{
System.Diagnostics.Debug.Write("Filling features.. \n");
foreach (ListViewItem item in ListView1.Items)
{
System.Diagnostics.Debug.Write("FOR \n");
CheckBox checkbox = (CheckBox)item.FindControl("Checkbox");
TextBox description = (TextBox)item.FindControl("descriptionTextbox");
//Try to get an existing relation
int featureId = Int32.Parse(((Label)item.FindControl("idLabel")).Text);
PlaceHasFeature phf = (from p in myEntities.PlaceHasFeature
where p.place_id == placeId && p.feature_id == featureId
select p).SingleOrDefault();
if (phf != null)
{
System.Diagnostics.Debug.Write("Checking " + phf.Feature.name + "\n");
//Relation exists
checkbox.Checked = true;
description.Text = phf.description;
}
else
{
System.Diagnostics.Debug.Write("Didn't find relation for " + featureId + "\n");
}
}
}
}
Console output:
When I open the link: Filling features...
After refresh: Filling features... FOR FOR FOR (...)
Anyone knows the cause of this?
I suspect the issue is due to the ASP.NET Page Life Cycle, where the page load event occurs before the individual controls load event:
The Page object calls the OnLoad method on the Page object, and then
recursively does the same for each child control until the page and
all controls are loaded. The Load event of individual controls occurs
after the Load event of the page.
I believe you have a couple of options. Move the fillFeatures method to the Page.LoadComplete Event:
The LoadComplete event occurs after all postback data and view-state
data is loaded into the page and after the OnLoad method has been
called for all controls on the page.
Or move the fillFeatures method to the ListBox's DataBound Event. Though I would suspect that the Page.LoadComplete Event is really the better of the two options.
Related
When I click btnGDynamicCont I want to load the first set of controls, then on each further click of that button, add a new control (textbox) alongside the other ones, so each time it is clicked I am adding a new textbox across state.
Do you know where I should add the creation of the new textbox in order to keep it after each postback?
{
protected void Page_Load(object sender, EventArgs e)
{
if (Convert.ToString(ViewState["Generated"]) == "true")
GenerateDynamicControls();
}
public void GenerateDynamicControls()
{
TextBox txtDynamic = new TextBox();
txtDynamic.ID = "txtDynamic";
txtDynamic.Text = "Dynamic TextBox";
Page.Form.Controls.Add(txtDynamic);
TextBox txtDynamic2 = new TextBox();
txtDynamic2.ID = "txtDynamic2";
txtDynamic2.Text = "Dynamic Textbox";
Page.Form.Controls.Add(txtDynamic2);
}
protected void btnGDynamicCont_Click1(object sender, EventArgs e)
{
if (Convert.ToString(ViewState["Generated"]) != "true")
{
GenerateDynamicControls();
ViewState["Generated"] = "true";
}
else
{
Response.Write("<h2>Controls are already exist in page</h2>");
}
}
}
}
Dynamic controls are usually recreated at the Page_Load method. For more information, please refer to the Dynamically Created Controls in ASP.NET article.
You can refer the below link where a very similar issue is addressed.
unable to add more than one server control dynamically in asp.net
Everytime a postback happens, you should recreate the already existing controls(dynamically added) in your page_load event and the new controls are to be created in the button_click event.
Use some logic to generate ids for the controls for the viewstate to be maintained. VIEWSTATE will be taken care automatically if the ids of the controls generated before and after postback are the same.
One way to keep track of the number of textboxes is to store the count in session.
i'm a beginner in .NET, and search since yesterday morning to resolve my problem without finding the solution.
Here is my problem :
I create dynamically some User Controls by this way, because I need to give parameters :
List<ANNOUNCEMENT> listAnnouncement = getAnnoucements();
foreach(ANNOUNCEMENT ann in listAnnouncement)
{
if(ann.IS_CURRENT_ANNOUNCEMENT && currentAnnouncement == null)
{
currentAnnouncement = ann;
}
List<Object> listParams = new List<Object>();
listParams.Add(ann);
AnnouncementPresentation ap = (AnnouncementPresentation)(Controller.LoadControl(Page, "~/UserControls/AnnouncementPresentation.ascx", listParams.ToArray()));
/* important for the end of the method */
ap.modifyAnnouncementButtonClick += new EventHandler(modifyAnnouncementButtonClick);
pnl_announcements.Controls.Add(ap);
}
In this ASCX, I have a button, and when user will click on it, I want to call a method contained in my ASPX, so I do this in the ASCX :
public event EventHandler modifyAnnouncementButtonClick;
protected void btn_modify_announcement_Click(object sender, EventArgs e)
{
PageAdminAnnonces.currentAnnouncement = annonce;
modifyAnnouncementButtonClick(sender, e);
}
And this in the ASPX :
protected void modifyAnnouncementButtonClick(object sender, EventArgs e)
{
initListOfAnnouncement();
lbl_errors.Text = currentAnnouncement.TITLE;
}
I think everything works, but there is the problem : It works once, and at the end of the method, I delete my ASCX as you can see, and create new ASCX. But they don't have the methods, and when I click again, nothing works, so the ASPX is reloaded. After reloading, it works again.
Do i do something wrong?
According to the information in the comments, I suppose that your solution does not work because you are recreating the controls in the Click event handling method, which is very late in the page's lifecycle and should not be used for adding controls.
As mentioned in the comments, I suggest you to create the controls in Page_Init or Page_Load and not recreate them in the button's Click handling method. You should also assign a unique ID to each of them. Then, in the Click handler, you can use FindControl method to acces the created controls. Alternatively you can just save the references to the controls upon creation, so you can access them later easily.
Useful links:
http://msdn.microsoft.com/en-us/library/ms178472.aspx
http://visualstudiomagazine.com/articles/2010/10/11/more-on-adding-controls-dynamically.aspx
I am fairly new to the asp.net and experimenting with it to learn the page life cycle. Here is a problem that I have been unable to resolve for past few days.
I have a hosting page (.aspx). Then I have two user controls (.ascx). The page has a place holder control in which it loads the user controls one at a time based on the application flow. First user control is loaded on application start up. It has a "continue" button. Continue button click loads the Second user control that has two buttons - "Back" and "Submit". Obviously the "Back" button should load the first user control again and Submit button should submit the form data. Pretty simple.
The problem is that the command button event handler that I have on the second user control is not firing the first time. (I have one event handler for both buttons). The load event of the user control fires but then it ignores the button click. If I click it again, then it fires. I re-load the controls on the page in every page_load. Here is some relevent code:
AddPlayer.aspx:
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Controls.Clear();
// Load the ctlInputPlayer control
Control ctlToAdd = LoadControl("ctlInputPlayer.ascx", null);
if (ctlToAdd != null)
{
_ctlInputPlayer = (ctlInputPlayer)ctlToAdd;
_ctlInputPlayer.SendPlayerData += new EventHandler(ctlInputPlayer_SendPlayerData);
PlaceHolder1.Controls.Add(_ctlInputPlayer);
}
// see if there is player data available in the view State
PlayerData player = (PlayerData)ViewState["Player"];
if (player != null)
{
ctlToAdd = LoadControl("ctlPlayerInfo.ascx", player);
if (ctlToAdd != null)
{
_ctlPlayerInfo = (ctlPlayerInfo)ctlToAdd;
_ctlPlayerInfo.SubmitPlayerData += new EventHandler(ctlPlayerInfo_SubmitPlayerData);
PlaceHolder1.Controls.Clear();
PlaceHolder1.Controls.Add(_ctlPlayerInfo);
}
}
}
ctlPlayerInfo.ascx (second user control):
ctlPlayerInfo.ascx.cs
protected void CommandBtn_Click(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case "Submit":
//submitPlayerData will fire here
break;
case "Back":
// editplayer data will fire here
break;
}
}
protected void Page_Load(object sender, EventArgs e)
{
// load control data here....
}
The page_Load fires every time but "CommandBtn_Click" doesn't fire after the first click. I have to do it click it again. It doesn't matter which order I click the buttons.
I appreciate the help. Let me know if more details are needed. Thanks!
You should load your user controls every time in Page_Init and set the ID property.
On a page I have:
<asp:TextBox runat="server" ID="EmailTextBox" AutoPostBack="true" OnTextChanged="EmailTextBox_Changed" />
<asp:Button runat="server" ID="SearchButton" OnClick="AddButton_Click" Text="add" />
In EmailTextBox_Changed, it counts up how many emails can be found, before running the search.
The problem is, when you type something in EmailTextBox, and click on the button, you have to click twice to get the actual results up. This is because the first click is doing the "AutoPostBack" part from the text box, and then you have to click again to make the actual click postback to happen.
Without removing the "AutoPostBack=true", how can I stop it needing two clicks in these circumstances?
I was looking for an answer to this issue as well. I ended up removing all autopostback=true and doing all the actions with JavaScript, same as you.
However, one of the things I experimented with before the JavaScript was something to maintain control focus after a postback. I noticed the hidden field I used to store the name of the control that had the last focus DID have the name of the search button (mine is a save button). So, while I'm still not sure how to get the 'search' function to fire 'automatically' like it should, which is basically to chain the postback events from both the textbox AND the button together one after another, I CAN know that the user clicked that save button before the postback happened (or tried to).
So, what you have on postback is your textbox event firing, and then the Page_Load method, or whatever page cycle method you want to use, where you can check to see what the last control to have focus was. With this, there are several ways you could implement a work around.
Off hand, you could add code in every event that fires from a control autopostback, like the textbox and the search button, to check the name of the focus control. If the control that had focus last is NOT the control's autopostback function we are running, we can set a page level bool called 'Run_Controls_Method' to TRUE, else, set it to false. This way we know we should run the control that had last focus postback method.
On page load, you could do something like:
if (Run_Controls_Method && hdfFocusControl.Value != "")
{
switch(hdfFocusControl.Value)
{
case "btnSearch":
btnSearch_OnClick(null, null);
break;
case etc.
}
}
The way I implement the hdfHasFocus is:
HTML:
<input id="hdfHasFocus" runat="server" type="hidden" />
HTML code behind:
protected void Page_PreRender(object sender,EventArgs e)
{
if (IsPostBack != true)
{
//Add the OnFocus event to all appropriate controls on the panel1 panel.
ControlManager.AddOnFocus(this.Controls,hdfHasFocus,true);
//other code...
}
ControlManager.SetFocus(this.Controls,hdfHasFocus.Value,true);
}
ControlManager.cs related code:
/// <summary>
/// Adds the onfocus event to the UI controls on the controls in the passed in control list.
/// </summary>
/// <param name="controls">The list of controls to apply this event.</param>
/// <param name="saveControl">The control whose .value will be set to the control.ID of the control which had focus before postback.</param>
/// <param name="Recurse">Should this method apply onfocus recursively to all child controls?</param>
public static void AddOnFocus(ControlCollection controls, Control saveControl, bool Recurse)
{
foreach (Control control in controls)
{
//To make the .Add a bit easier to see/read.
string action = "";
//Only apply this change to valid control types.
if ((control is Button) ||
(control is DropDownList) ||
(control is ListBox) ||
(control is TextBox) ||
(control is RadDateInput) ||
(control is RadDatePicker) ||
(control is RadNumericTextBox))
{
//This version ignores errors. This results in a 'worse case' scenario of having the hdfHasFocus field not getting a
// value but also avoids bothering the user with an error. So the user would call with a tweak request instead of
// and error complaint.
action = "try{document.getElementById(\"" + saveControl.ClientID + "\").value=\"" + control.ClientID + "\"} catch(e) {}";
//Now, add the 'onfocus' attribute and the built action string.
(control as WebControl).Attributes.Add("onfocus", action);
}
//The 'onfocus' event doesn't seem to work for checkbox...use below.
if (control is CheckBox)
{
//This version ignores errors. This results in a 'worse case' scenario of having the hdfHasFocus field not getting a
// value but also avoids bothering the user with an error. So the user would call with a tweak request instead of
// and error complaint.
action = "try{document.getElementById(\"" + saveControl.ClientID + "\").value=\"" + control.ClientID + "\"} catch(e) {}";
//In case there is already an attribute here for 'onclick' then we will simply try to add to it.
action = action + (control as WebControl).Attributes["onclick"];
//Now, add the event attribute and the built action string.
(control as WebControl).Attributes.Add("onclick", action);
}
//You don't seem to be able to easily work the calendar button wiht the keyboard, and it seems made for
// mouse interaction, so lets set the tab index to -1 to avoid focus with tab.
if (control is CalendarPopupButton)
{
(control as WebControl).Attributes.Add("tabindex", "-1");
}
//We also want to avoid user tab to the up and down spinner buttons on any RadNumericTextBox controls.
if (control is RadNumericTextBox)
{
(control as RadNumericTextBox).ButtonDownContainer.Attributes.Add("tabindex", "-1");
(control as RadNumericTextBox).ButtonUpContainer.Attributes.Add("tabindex", "-1");
}
//Recursively call this method if the control in question has children controls and we are told to recurse.
if ((Recurse) && (control.HasControls()))
{
AddOnFocus(control.Controls, saveControl, Recurse);
}
}
}
/// <summary>
/// Searches the ControlCollection passed in for a match on the ID name string passed in and sets focus on that control if it is found.
/// </summary>
/// <param name="controls">The collection of controls to search.</param>
/// <param name="FocusToID">The ID of the control to set focus on.</param>
/// <param name="recurse">Recursively search sub-controls in the passed in control collection?</param>
/// <returns>True means keep processing the control list. False means stop processing the control list.</returns>
public static bool SetFocus(ControlCollection controls, string FocusToID, bool recurse)
{
//Return if no control ID to work with.
if (string.IsNullOrEmpty(FocusToID) == true)
{ return false; }
//If we get here and don't have controls, return and continue the other controls if applicable.
if (controls.Count <= 0)
{ return true; }
foreach (Control control in controls)
{
//If this is the control we need AND it is Enabled, set focus on it.
if (((control is GridTableRow) != true) && //GridTableRow.ClientID throws an error. We don't set focus on a 'Row' anyway.
(control.ClientID == FocusToID) &&
((control as WebControl).Enabled))
{
control.Focus();
//return to caller. If we were recursing then we can stop now.
return false;
}
else
{
//Otherwise, see if this control has children controls to process, if we are told to recurse.
if ((recurse) && (control.HasControls()))
{
bool _continue = SetFocus(control.Controls, FocusToID, recurse);
//If the recursive call sends back false, that means stop.
if (_continue != true)
{ return _continue; }
}
}
}
//We are done processing all the controls in the list we were given...
// If we get here, then return True to the caller. If this was a recursive call, then
// the SetFocus in the call stack above will be told to continue looking since we
// didn't find the control in question in the list we were given.
return true;
}
In fact, you don't have to click on the button to make the first event happen.
Just 'leave' the textbox, i.e. with 'tabbing' out of it to make the AutoPostBack happen.
If you want to do both in a single postback just remove the Button and do the things you do in AddButton_Click also in the Textbox_Change event.
Making it a client side check was the solution to this...there doesn't seem to be a way to prevent it otherwise
Write below code in Page_Load event to prevent twice click
BtnSaveAndPrint.Attributes.Add("onclick", "return confirm('Are you sure you Want to Save & Print?');")
You could avoid this by not doing it server side and using Javascript. You also didn't post your page load event. Are you checking if it post back or not ?
Another way you could do this is the event that happens on the click of the button can be called from the TextChanged event and get rid of the button all together.
I had the same problem, I decided to move the click event code to the page load event and execute it in case of postback. And not to use a click event at all.
protected void Page_Load(object sender, System.EventArgs e)
{
if (IsPostBack)
{
// put code here
}
}
instead of :
public void ButtonClick(object sender, EventArgs e)
{
//...
}
Let me start with pointing out, this is not an easy question to answer. At least it's dead near impossible to find the answer.
In an UpdatePanel I dynamically add some controls to a panel control of mine.
List<Showing> showings = cBLL.GetShowings(tenant.Id);
int j = 1;
foreach(Showing showing in showings)
{
UserControl uc = (UserControl)Page.LoadControl("Controls/BookShowing.ascx");
uc.ID = "showing_" + j;
uc.Visible = true;
((BookShowing)uc).SetShowing(showing);
pnl_showings.Controls.Add(uc);
j++;
}
This all takes place in a button event fired from a control asychrone.
Below these fields I add in the code shown above I have a button. The button is also placed in the updatepanel. This button is called: btn_editShowings
Now when I come to the btn_editShowings_Click event handler, my dynamic added controls does not exist anymore. I have also tried catching them in the OnInit but they dont exist there either.
How the F... is it ever possible to obtains data from the dynamic added controls???
Is there anyway, and I don't care how lousy it performs or anything, to solve this?
UPDATE:
I have now tried to do the following which should work as Init fires before LoadViewState from what I have read.
I add some controls dynamic in a Button event
protected void Button2_Click(object sender, EventArgs e)
{
for (int i = j; i < showno + 4; i++)
{
UserControl uc = (UserControl)Page.LoadControl("Controls/BookShowing.ascx");
uc.ID = "showing_" + i;
uc.Attributes.Add("runat", "Server");
uc.EnableViewState = true;
uc.Visible = true;
pnl_showings.Controls.Add(uc);
}
UpdatePanel1.Update();
}
And I have done the same thing in my init function:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Session["ShowingsCount"] != null)
{
int noOfUCs = (int)Session["ShowingsCount"];
for (int i = 1; i < noOfUCs; i++)
{
UserControl uc = (UserControl)Page.LoadControl("Controls/BookShowing.ascx");
uc.ID = "showing_" + i;
uc.Attributes.Add("runat", "Server");
uc.EnableViewState = true;
uc.Visible = true;
pnl_showings.Controls.Add(uc);
}
UpdatePanel1.Update();
}
}
But when I try this:
FindControl("showing_1").Visible = false;
I get a null reference exception.
Best Regards
The Real Napster, troubled once again.
When you add the controls the first time, keep track of the number of controls you need to recreate in the viewstate.
On every post-back after that make sure you add that number of controls back onto the page with the same IDs in the LoadViewState method.
The key is that you always have to add dynamically created controls to the page every post-back and you have to do it before the viewstate loads in order for the controls to get their form-posted values loaded back into them.
BookShowing bs = (BookShowing)UpdatePanel1.FindControl("showing_" + i);
Was the solution, The OnInit override did actually work, it was me fetching the usercontrol the wrong way.
Closed.