creating dynamic control in asp.net - asp.net

I'm creating a fileupload control on a linKbutton click event. First time it's creating the controls, but if I press the link button second time, it's not creating. What is the problem with that? The following is my code:
protected void LinkButton1_Click(object sender, EventArgs e)
{
newattach();
}
private void newattach()
{
int i;
for (i = 0; i < 2; i++)
{
count++;
FileUpload f1 = new FileUpload();
f1.ID = "fileupload" + count.ToString();
f1.Height = 34;
f1.Width = 212;
Panel1.Controls.Add(f1);
}
}
and count is a static variable. Please help.

When you create controls dynamically with ASP.NET you need to recreate the control every time you post back, generally you recreate the control on Page_Load. That is most likely the cause of your problem.

Related

Page_PreLoad() event is triggered before link button click event when I click on a link button

I'm listing folders and files in drive E, I'm using a hidden field to keep the path, I created some link buttons representing folders, they are created programmatically on Page_PreLoad() event:
protected void Page_PreLoad(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(hdfPath.Value))
{
path = "E:\\" + hdfPath.Value;
directories = Directory.GetDirectories(path);
files = Directory.GetFiles(path);
}
else
{
directories = Directory.GetDirectories("E:\\");
files = Directory.GetFiles("E:\\");
}
for (int i = 0; i < directories.Length; i++)
{
LinkButton lkbLink = new LinkButton();
lkbLink.Click += new EventHandler(btn_Click);
void btn_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(hdfPath.Value))
hdfPath.Value = folderName;
else
hdfPath.Value += "\\" + folderName;
}
}
}
When I click in whichever link button, first of all Page_PreLoad() event is triggered then btn_Click() event, while I expected btn_Click() to be fired first. In that case the related value on hidden field belongs to the value of one step before.
Is something wrong with the ASP.Net life cycle I chose?
How can I make it immediately set the hidden filed value when user clicks on the link button so that the (correct) current value on hidden field be taken?
There is nothing wrong with the lifecycle and you can not choose a lifecycle either :)
The PreLoad-Event of the page is always before the control-events.
This will give you a detailed overview over the lifecycle in asp.net.
It's a little complicated in your case:
you need to add some buttons dynamically and attach event handlers to them - this has to be done on every postback, else the button-handlers won't be triggered.
Then in your handler you need to delete these before added buttons again and add the new ones according to the new path.
To achieve this, make a method from your code, e.g:
private void InitButtons()
{
if (!string.IsNullOrEmpty(hdfPath.Value))
{
path = "E:\\" + hdfPath.Value;
directories = Directory.GetDirectories(path);
files = Directory.GetFiles(path);
}
else
{
directories = Directory.GetDirectories("E:\\");
files = Directory.GetFiles("E:\\");
}
for (int i = 0; i < directories.Length; i++)
{
LinkButton lkbLink = new LinkButton();
lkbLink.Click += new EventHandler(btn_Click);
void btn_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(hdfPath.Value))
hdfPath.Value = folderName;
else
hdfPath.Value += "\\" + folderName;
// remove the old buttons here, if you need to
// RemoveOldButtons();
// call the Init-Buttons-Function again
InitButtons();
}
}
}
Call this method from your button event-handlers as shown above and again in your load-event-handler:
protected void Page_PreLoad(object sender, EventArgs e)
{
InitButtons();
}

why chk.Checked ChangedEventHandler is not triggered and i get the exception Object reference not set to an instance of an object

I try to make a simple application in which I have a dropdown list with tems - numbers from 1 to 4.
Depending on the number the user choose - I create dynamically this number of checkboxes with binded checkedchanged event. So when the user checks some of the checkboxes so checkedchanged event is raised and I store the text of the checked checkbox in session and then when I click a button I want to see the text only from the checked checkboxes.
But it seems that the checkedchanged event handler is never triggered.
Thank you in advance
public partial class proba : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
dd1.Items.Add("1");
dd1.Items.Add("2");
dd1.Items.Add("3");
dd1.Items.Add("4");
}
protected void dd1_SelectedIndexChanged1(object sender, EventArgs e)
{
int numTourists = Convert.ToInt32(dd1.SelectedItem.Text);
for (int i = 0; i < numTourists; i++)
{
CheckBox chk = new CheckBox();
chk.ID = "chk" + i;
chk.Text = "box" + i;
chk.CheckedChanged += new EventHandler(checkChanged);
Page.FindControl("form1").Controls.Add(chk);
}
}
protected void checkChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
lblpr.Text += chk.Text;
Session["chk"] = chk.Text;
}
protected void btnpr_Click(object sender, EventArgs e)
{
lblpr.Text = "length" + ((String [] )Session["chk"]).Length;
for (int k = 0; k < ((String[] )Session["chk"]).Length; k++)
{
lblpr.Text += ((String [])Session["chk"])[k];
}
}
}
You need to set AutoPostBack property of checkbox as true in order to post back when check changed
chk.AutoPostBack = true;
And read this also
adding an event handler to a dynamically created checkbox (aspx, c#)
change page load, you don't need to add items again and again in each page post back
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
//Load dd1
}
}
But you need to add dynamic controls on each page post back, better do it on OnInit as above answer in the link suggested
since you are creating checkbox dynamically, it get lost when there is the post back.
So you need to add those again before pageload event so that during page load event they are visible to .net and hence .net can fire their corresponding event.
B4 you dive into dynamic control it is good idea to get the basic which can be found at https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx

Get control which is generated on runtime

am creating some TextBoxes by backend on a text change event, Like this :
protected void txtHowMany_TextChanged(object sender, EventArgs e)
{
int totalSections = Convert.ToInt32(txtHowMany.Text.Trim());
for (int i = 1; i <= totalSections; i++)
{
TextBox tbx = new TextBox();
tbx.Text = "";
tbx.ID = "section" + i;
tbx.Style.Add("width", "90%");
tdSectionsAdd.Controls.Add(tbx);
}
trSectionsName.Visible = true;
}
The auto post back is true for txtHowMany, so when I enter a number, it generates the textboxes and add it to table division
Now the problem is, I am trying to get text from generated textboxes like this :
protected void btnSave_click(object sender, EventArgs e)
{
int numbersOfSectionsToSave = 1;
int sectionsToSave =Convert.ToInt32(txtHowMany.Text.Trim());
for (int i = 1; i < sectionsToSave; i++)
{
Sections section = new Sections();
section.CourseId = result;
section.OrganizationId = course.OrganizationId;
foreach (Control c in tdSectionsAdd.Controls)
{
if (c.GetType() == typeof(TextBox))
{
TextBox txtBox = (TextBox)c;
string id = "section" + i;
if (txtBox.ID == id)
{
section.Name = txtBox.Text.Trim();
}
}
}
string name = Request.Form["section1"];
section.CreatedBy = "Admin";
section.CreationDate = DateTime.Now;
section.ModifiedBy = "Admin";
section.ModificationDate = DateTime.Now;
numbersOfSectionsToSave += section.SaveSection();
}
But its showing 0 count for the controls in tdSectionsAdd , The controls are added before I am trying to access them, but still it shows no controls in td.
Please help, How can I get these textboxes?
Thanks!
You need to add them in each postback. Store the totalSections variable in ViewState so you can add them i page load also:
protected void AddTextBoxes()
{
int totalSections;
if (int.TryParse(Convert.ToString(ViewState["TotalSections"]), out totalSections)
{
for (int i = 1; i <= totalSections; i++)
{
TextBox tbx = new TextBox();
tbx.Text = "";
tbx.ID = "section" + i;
tbx.Style.Add("width", "90%");
tdSectionsAdd.Controls.Add(tbx);
}
trSectionsName.Visible = true;
}
}
protected void txtHowMany_TextChanged(object sender, EventArgs e)
{
ViewState["TotalSections"] = Convert.ToInt32(txtHowMany.Text.Trim());
tdSectionsAdd.Controls.Clear();
AddTextBoxes();
}
protected void Page_Load(object sender, EventArgs e)
{
AddTextBoxes();
}
Dynamic Created controls "Disappear" on postback, if they are not "recreated" in the Page_Init of that page.
Only if they are created in the page_init will the page's viewstate get updated with their information.
Long Explantion:
When we perform a postback (or partial postback) we want to be able to access those controls (or at least the values the user put into them).
We know that the data is in the viewstate, but ASP.NET doesn’t really know which control a ViewState item belongs to. It only knows to match a viewstate item and a control through the same index (e.g. Matches item n in the viewstate tree to item n in the control tree). Therefore in order to get the dynamic controls' data, we need to re-create the controls each time the page is postbacked.
BUT in order for this to work, we need to re-create the controls in the Page_Init function NOT in the Page_Load.
Why? Because when the ViewState is created it needs all the controls to already exist.
This is taken from MSDN, as you can see the viewstate is loaded AFTER the init but before the page load.
TL;DR Call the function that creates the dynamic controls in the page_init and you should be able to see all the values the user entered when the page postbacks
A few links on this issue:
http://forums.asp.net/t/1186195.aspx/1
ASP.NET - Dynamic controls created in Page_Pre_init() or Page_Init() or Page_Load()
Option 2:
I should note: If the controls all had unique Ids and you're not interested in re-creating them again every postback - you could always look for them in the Request Object.
The Request.Form is a NameValueCollection that holds the values of all the controls that were part of the form, just search it for whatever you're looking for

Dynamically created rows disappear from Gridviews on update/delete

Situation: I have several Gridviews on one page, and each Gridview has a dynamically created row to display the totals at the bottom. In each case, the totals row is created on a RowDataBound event. The strategy that I am using is like the one provided by Mike Dugan on his Blog.
The following is the code for one of the GridViews, but the others all do something very simular.
protected void gvWorkerHours_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Keep running total of hours.
if (e.Row.RowType == DataControlRowType.DataRow)
{
totalBillableHours += Convert.ToDouble(DataBinder.Eval(e.Row.DataItem, "Hours"));
}
if (e.Row.RowType == DataControlRowType.Footer)
{
int numColumns = gvWorkerHours.Columns.Count;
int hoursIndex = 4; //5th column, 0-based
int rowIndex = gvWorkerHours.Rows.Count + 1;
CreateTotalRow((Table)e.Row.Parent, rowIndex, totalBillableHours, hoursIndex, numColumns);
}
}
private void CreateTotalRow(Table table, int rowIndex, double totalValue, int totalIndex, int numColumns)
{
TableCell[] cells = new TableCell[numColumns];
for (int i = 0; i < numColumns; i++)
{
TableCell cell = new TableCell();
Label label = new Label();
label.Font.Bold = true;
if (i == 0)
{
label.Text = "Total";
}
else if (i == totalIndex)
{
label.Text = totalValue.ToString();
}
else
{
label.Text = "";
}
cell.Controls.Add(label);
cells[i] = cell;
}
GridViewRow row = new GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal);
row.Cells.AddRange(cells);
table.Rows.AddAt(rowIndex, row);
}
Problem: If a user clicks on an edit/delete command for any row on any of these Gridviews, it will make the totals row disappear for all other Gridviews. As I understand, this is because a PostBack is occurring, however the RowDataBound events will not occur for the other GridViews, rather they will just reload their data from the ViewState, which does not contain the totals.
Failed attempts at solving: I cannot simply call DataBind on each of the GridView during a PostBack, because that will prevent the update/delete from occurring. Although the RowCreated event will occur for the GridViews during a PostBack, this event in not sufficient because the GridViews will not have data bound and will throw an exception when I try to calculate the total. Disabling the ViewState for these GridViews seems like a solution, however there will be a lot of data to reload each time a user clicks a command. Manually saving my data to the ViewState also seems like a solution, but there does not seem to be a simple way to have the GridViews retrieve this custom data on a PostBack.
Is there any way to actually achieve what I am trying to do with ASP.NET? It seems like a simple requirement to have a totals row at the bottom of each GridView.
Thanks in advance for any help.
What if you try creating the dynamic row using the gridView.OnPreRender event instead of the gridView.RowDataBound event. This way your data you need to calculate your dynaimic row results is available but the html has not been sent to the web browser yet. Please post some more code so we can provide more insight into fixing your issue.
As recommended, I tried putting the code to create the totals row in the PreRender event rather than the RowDataBound event. This seemed to work, except that it broke all of the commands for the GridView that it was used on. It appears that manually changing the GridView disrupts its automatic behavior.
protected void gvWorkerHours_PreRender(object sender, EventArgs e)
{
double total = 0;
int numColumns = gvWorkerHours.Columns.Count;
int hoursIndex = 4; //5th column, 0-based
int rowIndex = gvWorkerHours.Rows.Count + 1;
foreach (GridViewRow row in gvWorkerHours.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
Label label = (Label)row.FindControl("lblHours");
total += Convert.ToDouble(label.Text);
}
}
CreateTotalRow((Table)gvWorkerHours.Rows[0].Parent, rowIndex, total, hoursIndex, numColumns);
}
OK, the way I ended up solving this was with JQuery. If anybody else is facing a similar problem, remember that the totals must be calculated when the DOM is ready, as well as at the end of any postback. To handle the postback situation, you can just call the Javascript on the client using ScriptManager.RegisterStartupScript().
Again, I had four GridViews in my circumstance, but I'll just show the JQuery code for one of them:
$(document).ready(function () {
setTotals();
});
function setTotals() {
var totalHours = getBillableHoursTotal();
if (isNaN(totalHours)) totalHours = '...editing';
$('#spanBillableHoursTotal').html(totalHours);
//... etc.
}
function getBillableHoursTotal() {
var total = 0.0;
var rows = $('table[id*="_gvWorkerHours"] tr.RegularRows');
$(rows).each(function () {
total = total + parseFloat($(this).children('td').children('span[id*="lblHours"]').html());
});
return total;
}
And for the C# on the code behind:
protected void Page_Load(object sender, EventArgs e)
{
// ... preceeding Page Load code
if (IsPostBack)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "?", "setTotals()", true);
}
}

datalist custom paging in asp.net

I am doing custom paging for a datalist.Below method gets the required page numbers.
My problem is the click event is not being fired during debug.
Can anyone tel where the problem is.
private void BindPageNumbers(int TotalRecords)
{
int counter = 0;
for(int i=0;i<TotalRecords;i=i+5)
{
counter=counter+1;
LinkButton lnk = new LinkButton();
lnk.Click += new EventHandler(lbl_click);
lnk.ID = "lnkPage" + (counter).ToString();
lnk.Text = (counter).ToString();
pages.Controls.Add(lnk);
Label spacer = new Label();
spacer.Text = " ";
pages.Controls.Add(spacer);
}
}
void lbl_click(object sender, EventArgs e)
{
LinkButton lnk = sender as LinkButton;
int Currentpage = int.Parse(lnk.Text);
ListDataBinding_paging(2, this.Days, (Currentpage-1)*5, 5);
}
Here "ListDataBinding_paging" is the method from where the datalist is being filled.
You are creating your page link buttons dynamically. So they need to be re-created in every post-back early in the life-cycle. I suspect that BindPageNumbers is getting called after the post event data is processed and hence the click event does not get generated.
I suggest you to invoke BindPageNumbers in page_load for creating your buttons early in the life cycle. You can store the total records count in the view-state. If page_load doesn't help then try LoadViewState override - put the code after call to base implementation - something like
protected override void LoadViewState(Object savedState)
{
base.LoadViewState(savedState);
BindPageNumbers((int)ViewState["TotalRecords"]);
}

Resources