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.
Related
I want to dynamically create buttons for each cell in a table, which works fine. The problem is that i now want to assign them server side click events, like this:
Button b = new Button();
b.Text = "Delete";
b.CssClass = "btnDelete";
b.Click += new EventHandler(this.deletePictures_Click);
While this would be my deletePictures_Click:
private void deletePictures_Click(object sender, EventArgs e)
{
test.Text = "hi";
}
But it won't fire. I did quite some research but couldn't find anything that helped me, yet. Do you guys know what's wrong?
Thanks in advance!
Edit:
Here's the rendered HTML
<td class="resultCell">
<img class="resultpicture" src="photos/DSC_101.jpg">
<input name="ctl00$cphContentBox$ctl02" value="Delete" class="btnDelete" type="submit"></td>
Edit:
I saved all the buttons in a List and then in the Session. In the OnInit I iterated the List, assigning the Button.OnClientClick to each of them. But the event still won't fire! Here's the code:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Session["buttons"] != null)
{
buttons = (List<Button>)Session["buttons"];
for (int i = 0; i < buttons.Count; i++)
{
buttons[i].OnClientClick += new EventHandler(deletePictures_Click);
}
}
}
The easy idea is to use a grid-view instead a table.
In the above problem you need to recreate you element on pre_init evetn.
Here is a good link
http://social.msdn.microsoft.com/Forums/en-US/dbc12b8c-8796-4800-a45f-57f24b8ef72b/dynamically-created-button-event-is-not-working
you need to create an array of objects (i think a collection of them), then cycle them with a foreach construct
at school i did it in java, printing buttons in a table with foreach and collections
I don't seem to know how to correctly write bn_pwd.Click and to make it work. Please help me.
protected void bn_pwd_Click(object sender, EventArgs e)
{
if (bn_pwd.Click == true)
{
lb_showpwd.Visible = true;
tb_Spwd.Visible = true;
lb_showcfmpwd.Visible = true;
tb_Scfmpwd.Visible = true;
}
else
{
lb_showpwd.Visible = false;
tb_Spwd.Visible = false;
lb_showcfmpwd.Visible = false;
tb_Scfmpwd.Visible = false;
}
}
When the bn_pwd_Click function is fired, it means that the button was clicked. What you want to do with bn_pwd.Click == true ?
Maybe you should use a variable to store the state of the controls you want to apply.
What you have will work (minus some unnecessary code), assuming you have a button with OnClick="bn_pwd_Click":
<asp:Button ID="bn_pwd" OnClick="bn_pwd_Click" Text="Submit" runat="server" />
Alternatively, you can declare the Click event in the code behind (and not have it in the code-front as above). Personally, I like having it on the code-front side.
bn_pwd.Click += bn_pwd_Click;
Now, when the button is clicked, the page will post-back (your Page_Load will execute again), and then bn_pwd_Click will execute. So you only need this:
protected void bn_pwd_Click(object sender, EventArgs e)
{
lb_showpwd.Visible = true;
tb_Spwd.Visible = true;
lb_showcfmpwd.Visible = true;
tb_Scfmpwd.Visible = true;
}
Because that function only ever runs when the button is clicked. I assume the visibilities of all of those controls should be set to false to begin with. Either in code front or in Page_Load.
From your question, it seems like you need to review the ASP.NET Page Life Cycle and could also benefit from some tutorials, like at ASP.net.
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 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.
I have a foreach loop in the Page_Load method of my one page to determine whether to Enable a button or not.
Code:
foreach (var class in classes)
{
for (var i = studentsList.Count - 1; i >= 0; i--)
{
if (studentsList[i].Id == class.student_id)
studenstList.Remove(studentsList[i]);
}
}
if (studentsList.Count == 0)
{
button1.Enabled = false;
button1.Text = "a";
}
else
{
button1.Enabled = true;
button1.Text = "b";
}
if (Page.IsPostBack) { return; }
The issue:
The value of studentsList.Count is lagging behind by a postback. If after the loop it should be 1, it only has the value of 1 at the next postback. I've debugged to confirm this is the case.
You can move this foreach loop to the Page_PreLoad method and give it a try.
Here anof life cycle of an ASP.NET page: http://msdn.microsoft.com/en-us/library/ms178472.aspx#lifecycle_events
I guess the student list is updated by clicking a button on the page.
Put the code that enables button1 on the button_click event of that button.
Does the button press edit students list? If so, the code for the button press will be fired after the Page_Load code.
Your problem is that you should wait for a corresponding event and write this logic in that event handler. For clarity, page load happens earlier than control events.