Dynamically Created Textboxes not updating - c#

I'm creating textboxes in the Page_Load event and giving them values, however whenever I load the details I am getting the same output. I always seem to get the first output I got, even on subsequent searches.
Here's what my code with the irrelevant information missing:
Textbox txtName = New Textbox();
protected void Page_Load(object sender, EventArgs e)
{
LoadData();
}
void LoadData()
{
txtName.Text = DropDownList.SelectedValue;
tableCell.Controls.Add(txtName);
}
If DropDownList has two values (e.g. "Item 1" and "Item 2") and has autopostback enabled, first time it will generate and show "Item 1" in the textbox (the default value for the DropDownList), but if this is changed and the autopostback fires, the textbox does not change.
I've tried getting around this by creating a new TextBox, overriding the "LoadPostData" function to prevent this from loading, which got around the issue there, but then I couldn't view the data afterwards.
Any idea how I could get around this? I may be approaching this in the wrong way.
Edit: I've added another item to DropDownList that removes TextBox, so that it can be re-created again. It seems to show the correct data when it is re-created after being removed, but if I'm attempting to just edit it, this isn't updating correctly.
Edit2: Here's the rest of the code for this page in case this helps at all. The objects which I'm having issues with are SBUName and SBUComments, which are both TextBoxes. The same issue is also happening for SBUClientDropdown but I believe the resolution will be similar:
DBHandler DBHandler = new DBHandler();
List<string> clients = new List<string>();
List<string> clientGroups = new List<string>();
List<string> sbus = new List<string>();
// Objects for SBU changes
string previousSBU = "";
string previousSBUClient = "";
TextBox SBUName = new TextBox() { ID = "SBUName" };
TextBox SBUComments = new TextBox() { ID = "SBUComments" };
DropDownList SBUClientDropdown = new DropDownList();
protected void Page_Load(object sender, EventArgs e)
{
clients = DBHandler.GetClients();
clientGroups = DBHandler.GetClientGroups();
if (!Page.IsPostBack)
{
foreach (string client in clients)
{
SBUClientList.Items.Add(GenerateItem(client));
ClientList.Items.Add(GenerateItem(client));
}
foreach (string clientGroup in clientGroups)
ClientGroupList.Items.Add(GenerateItem(clientGroup));
}
if ((SBUClientList.SelectedValue.ToString() != previousSBUClient) || (SBUList.SelectedValue.ToString() != previousSBU))
{
previousSBUClient = SBUClientList.SelectedValue.ToString();
previousSBU = SBUList.SelectedValue.ToString();
sbus = DBHandler.GetSBUs(SBUClientList.SelectedValue);
SBUList.Items.Clear();
foreach (string sbu in sbus)
SBUList.Items.Add(GenerateItem(sbu));
LoadSBU();
}
}
void LoadSBU()
{
if ((SBUClientList.SelectedValue.Trim().Length > 0) && (SBUList.SelectedValue.Trim().Length > 0))
{
Entity thisSBU = DBHandler.GetSBUInformation(SBUClientList.SelectedValue, SBUList.SelectedValue);
SBUTable.Rows.Add(GenerateHeaderRow("Client Name", "SBU Name", "Comments"));
SBUClientDropdown.Items.Clear();
foreach (string client in clients)
SBUClientDropdown.Items.Add(GenerateItem(client));
SBUClientDropdown.SelectedValue = SBUClientList.SelectedValue;
SBUClientDropdown.SelectedIndex = SBUClientList.SelectedIndex;
TableCell SBUClientCell = new TableCell();
SBUClientCell.Controls.Add(SBUClientDropdown);
SBUName.Text = thisSBU.sSBUName;
TableCell SBUNameCell = new TableCell();
SBUNameCell.Controls.Add(SBUName);
SBUComments.Text = thisSBU.sSBUComments;
TableCell SBUCommentsCell = new TableCell();
SBUCommentsCell.Controls.Add(SBUComments);
SBUTable.Rows.Add(GenerateRow(SBUClientCell, SBUNameCell, SBUCommentsCell));
Button SBUSaveButton = new Button();
SBUSaveButton.Click += new EventHandler(this.SBUSaveChanges);
SBUSaveButton.Text = "Save SBU Changes";
TableCell SBUButtonCell = new TableCell();
SBUButtonCell.Controls.Add(SBUSaveButton);
SBUButtonCell.ColumnSpan = 3;
TableRow SBUFooter = GenerateRow(SBUButtonCell);
SBUFooter.TableSection = TableRowSection.TableFooter;
SBUTable.Rows.Add(SBUFooter);
}
}
void ShowMessage(string message)
{
OutputString.Text = "<div class=\"message\">" + message + "</div>";
}
ListItem GenerateItem(string input)
{
ListItem output = new ListItem();
output.Text = input;
return output;
}
TableCell GenerateCell(string text)
{
TableCell output = new TableCell();
output.Text = text;
return output;
}
TableRow GenerateRow(params TableCell[] cells)
{
TableRow output = new TableRow();
foreach (TableCell cell in cells)
output.Cells.Add(cell);
return output;
}
TableRow GenerateHeaderRow(params string[] columns)
{
TableRow output = new TableRow();
output.TableSection = TableRowSection.TableHeader;
foreach (string column in columns)
{
TableCell thisCell = new TableCell();
thisCell.Text = column;
output.Cells.Add(thisCell);
}
return output;
}

previousSBUClient and previousSBU will always be blank on each post back, so why do you compare against them on the Page_Load? If you want their values saved between postbacks you need to save them in ViewState, I suggest code like:
public string PreviousSBU
{
get { return Convert.ToString(ViewState["PreviousSBU"] ?? string.Empty); }
set { ViewState["PreviousSBU"] = value; }
}
Perhaps its because you add multiple header rows to the table, and only the contents between the first through the second get displayed? Any header rows after added don't get displayed?
On each postback you add a new header row. But the TextBox's are created on each postback and not saved between, so you shouldn't be seeing anything at all if thats the case.

To render txtName to the page, you should have something like:
this.Controls.Add(txtName); somewhere on the page, preferably in the Page_Init, though for what you've listed, at least before the LoadData() call in Page_Load.

Taking a guess at the missing code but are you databinding your dropdown list? If you are you may be doing it every time instead of just when the page is not a postback. Like I say, guessing at what's not in your question but you might want consider something like this instead:
if (!Page.IsPostback)
{
MyDropDownList.DataSource = blah;
MyDropDownList.DataBind();
}
myTextBox.Text = MyDropDownList.SelectedValue;

Create your controls in OnInit event, becouse viewstate serialization happens between oninit and onload. Also check if it is postback, to avoid overwriting values from viewstate.

I remember strange things happening if you don't supply an ID to the textbox, are you doing this?
txtName.ID="txtName";`

Related

Checkbox fires more than one event

I have a dynamic tab where I have checkboxes. I put an event onCheckedChanged on them. It works first time, but after postback, my tab is recreated and when I click on another checkbox, I get more than one event being triggered.
Here is the code to create the tab :
private void initCatalog()
{
foreach (Article art in listArticle)
{
TableRow ligne = new TableRow();
ligne.Width = Unit.Percentage(100);
TableCell celluleITMREF = new TableCell();
celluleITMREF.Width = Unit.Percentage(10);
celluleITMREF.Text = art._ITMREF;
TableCell celluleCBOX = new TableCell();
celluleCBOX.Width = Unit.Percentage(8);
CheckBox cbox = new CheckBox();
cbox.ID = "cbox." + f._FOURNISSEUR + "." + art._ITMREF;
cbox.Checked = hfArticlesPaniers.Value.Contains(cbox.ID);
//cbox.Enabled = !(hfArticlesPaniers.Value.Contains(cbox.ID));
cbox.CheckedChanged += new EventHandler(cbox_CheckedChanged);
cbox.AutoPostBack = true;
cbox.CssClass = "c";
celluleCBOX.Controls.Add(cbox);
ligne.Cells.Add(celluleITMREF);
ligne.Cells.Add(celluleCBOX);
tabArticle.Rows.Add(ligne);
}
}
Here is the event for the checkbox :
protected void cbox_CheckedChanged(object sender, EventArgs e)
{
CheckBox c = sender as CheckBox;
Response.Write("<script>alert(\"" + c.ID + "\");</script>");
}
Here is the page_Load event :
protected void page_Load(object sender, EventArgs e){
this.initCatalog();
}
Thanks for your help :)
Each iteration of art in listArticle will cause the event handler to be added to the event by the line
cbox.CheckedChanged += new EventHandler(cbox_CheckedChanged);
executing each time. (i.e. you're adding the handler multiple times)
In addition, each running of initCatalog will also cause this if the page is not destroyed and loaded again in between.
Move the above line to a place where it will only be executed once after the page loads.
EDIT
on re-reading your code, adding multiple times within the loop is probably what you intended as there are multiple checkboxes. But after the postback, the initCatalog() may be executed again, thereby adding the event once more?
I found the mistake. I've a method who order the list after she was create ... I deleted the method and it worked.
I don't know why it made mistakes ...
private void orderCatalog()
{
var tab = from TableRow tr in tabArticle.Rows
orderby tr.Cells[1].Text
select tr;
List<TableRow> l = new List<TableRow>();
foreach (TableRow tr in tab)
{
l.Add(tr);
}
tabArticle.Rows.Clear();
foreach (TableRow tr in l)
{
tabArticle.Rows.Add(tr);
}
}

How to retrieve data from tablecell ASP.NET

When I load the page I send the number of rows the table will have:
protected void Page_Load(object sender, EventArgs e)
{
string numFilas = Request.QueryString["filas"];
tblAdd.Visible = true;
for (int i = 0; i < int.Parse(numFilas); i++)
{
TableRow NewRow1 = new TableRow();
TableCell NewCell1 = new TableCell();
TableCell NewCell2 = new TableCell();
TextBox txtBox1 = new TextBox();
txtBox1.Width = 200;
TextBox txtBox2 = new TextBox();
txtBox2.Width = 200;
// adding lebel into cell
NewCell1.Controls.Add(txtBox1);
NewCell2.Controls.Add(txtBox2);
// adding cells to row
NewRow1.Cells.Add(NewCell1);
NewRow1.Cells.Add(NewCell2);
tblAdd.Rows.Add(NewRow1);
}
}
now when I click submit I'd like to retrieve the data of the textbox inside the table, what I've been capable of is this:
public void submit(Object sender, EventArgs e)
{
for (Int32 i = 0; i < tblAdd.Rows.Count; i++)
{
TableRow dr = tblAdd.Rows[i];
TableCell hhh = dr.Cells[0];
String textCell = hhh.Text();
}
}
However, the text in the cells is empty because the text the user writes is IN the textbox, which I don't know how to get it.
Try this
While creating your text boxes add an ID
E.g.
txtBox1.ID = "txtBox1";
Then you can easily find this TextBox control from the current Cell's Controls collection as follows.
string textCell = ((TextBox)dr.Cells[0].FindControl("txtBox1")).Text;
Hope you understood what I'm trying to say. Basically, you need to find your control in the Cell.
Vote and accept the answer if it solved your issue.
Cheers!

find dynamically added controls

I'm adding dropdownlists to my page depending on a amount of database entries and when I press the button I want to get the selected values in each dropdownlist.
I tried this
foreach(DropDownList a in Form.Controls.OfType<DropDownList>())
{
Response.Write(a.SelectedValue);
}
but it doesn't find any dropdownlist on the page. Below is the code I use to add the dorpdownlists.
protected void Page_Init()
{
string product = Request.QueryString["product"];
foreach (productoption r in dbcon.GetOption(product))
{
TableRow row = new TableRow();
TableCell cel1 = new TableCell();
TableCell cel2 = new TableCell();
DropDownList dropdown1 = new DropDownList();
dropdown1.CssClass = "productdropdown";
foreach (suboption f in dbcon.GetSubOption(r.ProductOptionID))
{
dropdown1.Items.Add(f.SubOptionName + " +$" +f.SubOptionPrice);
}
cel1.Text = "<b>" + r.OptionName + "</b>";
cel2.Controls.Add(dropdown1);
row.Cells.Add(cel1);
row.Cells.Add(cel2);
Table1.Rows.Add(row);
}
TableRow row2 = new TableRow();
TableCell cell3 = new TableCell();
Button cartbutton = new Button();
cartbutton.ID = product;
cartbutton.CssClass = "btn_addcart";
cartbutton.Click += cartbutton_OnClick;
cartbutton.Text = "Add to cart";
cell3.Controls.Add(cartbutton);
row2.Cells.Add(cell3);
Table1.Rows.Add(row2);
}
foreach (TabelRow row in Table1.Rows)
{
if(row.Cells.Count > 0)
{
if (row.Cells[1].Controls.Count > 0 && row.Cells[1].Controls[0].GetType() == typeof(DropDownList))
{
Response.Write(a.SelectedValue);
}
}
}
First you should make a function that looks for a control type in a ControlCollection and returns a list of found controls. Something like that:
public List<T> GetControlsOfType<T>(ControlCollection controls)
{
List<T> ret = new List<T>();
try
{
foreach (Control control in controls)
{
if (control is T)
ret.Add((T)((object)control));
else if (control.Controls.Count > 0)
ret.AddRange(GetControlsOfType<T>(control.Controls));
}
}
catch (Exception ex)
{
//Log the exception
}
return ret;
}
and then you can get all DropDownList like that:
List<DropDownList> ret = GetControlsOfType<DropDownList>(this.Page.Controls);
I hope it helped.
You should be adding controls inside another control for example a panel
*Also you dont need to define controls at page init, you can do that at page load and they will retain their value*
protected void Page_Load(object sender, EventArgs e)
{
loadControls();
}
//For Instance lets take a dropdownlist and add it to a panel named testpanel
Protected void loadControls()
{
DropdownList ddlDynamic = new DropdownList();
//give this control an id
ddlDynamic.Id = "ddlDynamic1"; // this id is very important as the control can be found with same id
//add data to dropdownlist
//adding to the panel
testpanel.Controls.Add(ddlDynamic);
}
//Now we have to find this control on post back for instance a button click
protected void btnPreviousSet_Click(object sender, EventArgs e)
{
//this will find the control here
//we will you the same id used while creating control
DropdownList ddlDynamic1 = testpanel.FindControl("ddlDynamic1") as DropdownList;
//can resume your operation here
}

Cant fire dropDownList selectionChange event from Backend

I'm not able to fire the method on Selection-change. I'm adding the DropDownList itself from code behind. Code :
private TableCell CreateMTPLTypeCell(int insurerId, string MTPLType)
{
TableCell rg = new TableCell();
rg.ID = string.Concat("rg_", insurerId);
rg.CssClass = "formItem";
//if (insurerId == 14)
//{
DropDownList ddl = new DropDownList();
ddl.ID = "MTPLTypes";
ddl.Items.Add(new ListItem("Standard", "1")); // add list items
ddl.Items.Add(new ListItem("DubultOCTA", "2"));
ddl.Items.Add(new ListItem("DubultOCTA+vējst", "3"));
//ddl.SelectedIndex =
// ddl.Items.IndexOf(ddl.Items.
// FindByValue(MTPLType));
ddl.SelectedIndexChanged += new EventHandler(MTPLType_selectedIndexChange);
ddl.AutoPostBack = true;
rg.Controls.Add(ddl);
//}
return rg;
}
void MTPLType_selectedIndexChange(object sender, EventArgs e)
{
DropDownList ddl = (DropDownList)sender;
int insurerId = Int32.Parse(ddl.ID.Replace("rg_", ""));
MTPLQuotes quotes = proposal.Properties.MtplQuotes[insurerId];
if (quotes == null) return;
proposal.GetSingleMTPLQuote(insurerId, Helpers.PortalUtilities.CurrentUser, BrokerInfo.GetBrokerInfo().Country.ID);
DrawMtplQuotes(mtplPaymentMappingsCount > 0);
}
Do I miss some extra parameters on DropDownList object ?
Atm it works like that: After selectionChange it starts "loading" but it dosnt reach to the method. :/
In same class i have antoher tableCell with onChange event (Text_Change) -> this works ok.
private TableCell CreateInsurerMtplDiscountCell(int insurerId, decimal discount)
{
TableCell c = new TableCell();
c.CssClass = "formItem";
c.Style[HtmlTextWriterStyle.PaddingLeft] = "25px";
TextBox txt = new TextBox();
txt.ID = string.Format("ins_disc_{0}", insurerId);
txt.Text = discount > 0 ? discount.ToString() : "";
txt.TextChanged += new EventHandler(insurerDiscountPercent_TextChanged);
txt.AutoPostBack = true;
txt.Width = new Unit(40);
c.Controls.Add(txt);
Literal l = new Literal();
l.Text = "%";
c.Controls.Add(l);
return c;
}
void insurerDiscountPercent_TextChanged(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
int insurerId = Int32.Parse(txt.ID.Replace("ins_disc_", ""));
MTPLQuotes quotes = proposal.Properties.MtplQuotes[insurerId];
if (quotes == null) return;
decimal discountPercent;
if (!Decimal.TryParse(txt.Text, out discountPercent))
discountPercent = 0;
quotes.InsurerDiscountPercent = discountPercent;
foreach (MTPLQuote quote in quotes.Quotes)
ApplyMtplInsurerDiscount(quote, discountPercent);
DrawMtplQuotes(mtplPaymentMappingsCount > 0);
}
Got it fixed - The problem was about TableCell.ID (rg.ID = string.Concat("rg_", insurerId);) . After removing it everything worked fine. Anyone know why is that so ?
I think you have to refresh your Website after creating a new control.
i would suggesst you to use AJAX-updatepanels (so you dont have to refresh the whole site).
to add the OnChanged-Event Name you should also be able to add a string Name instead of the eventhandler itselfe.
ddl.SelectedIndexChanged = "MTPLType_selectedIndexChange";
I think you have to use "protected void" instead of "private void" its not reachable for the control cause of the permission restriction.
You should be binding your SelectedIndexChanged event to the dropdown list on the Page_PreInit event.
Then it should work.

change controls based on database value

Problem:
I have a value in a database table. This value can either contain a number, or null. If its null I would like to show one group of controls. If its not null I would like to show another group of controls.
Previous Attempts:
I have tried creating the controls in the code behind depending on the value of the database. This worked. However, on postback I get a null reference exception. The control doesn't exist on postback because the page is stateless. I'm building the controls in the page_load handler (depending on the value of the table column). Since I'm creating the controls in the page_load shouldn't they exist on postback?
I also tried recreating the controls in the event handler for the button. I get a "theres already a control with this id" exception (presumably because I already created it in the page_load method).
I read a few posts about how I have to store the controls in a session. This seems like more work than it should be.
Questions:
Am I going about this the wrong way? This seems like it should have been simple but is turning into a mess.
If this is the correct way to do this, Where do I add the session information? I've been reading other posts and I'm kind of lost
Code:
int bookId;
string empName;
protected void Page_Load(object sender, EventArgs e)
{
if(int.TryParse(Request.QueryString["id"], out bookId))
{
//This is where the value in the database comes into play. If its null Book.GetCopyOwner
// returns a string with length 0
empName = Book.GetCopyOwner(bookId, Request.QueryString["owner"]);
if (empName.Trim().Length > 0)
{
CreateReturnControls();
}
else
{
CreateCheckoutControls();
}
}
}
protected void ReturnButton_Click(object sender, EventArgs e)
{
}
protected void CheckOut_Click(object sender, EventArgs e)
{
int bookId;
if (int.TryParse(Request.QueryString["id"], out bookId))
{
TextBox userId = (TextBox)this.Page.FindControl("UserId");
//WHEN I TRY TO USE THE TEXTBOX userId HERE, I GET NULL REFERENCE EXCEPTION
BookCopyStatusNode.Controls.Clear();
CreateReturnControls();
}
}
protected void CopyUpdate_Click(object sender, EventArgs e)
{
}
private void CreateCheckoutControls()
{
TextBox userId = new TextBox();
//userId.Text = "Enter Employee Number";
//userId.Attributes.Add("onclick", "this.value=''; this.onclick=null");
userId.ID = "UserId";
Button checkOut = new Button();
checkOut.Text = "Check Out";
checkOut.Click += new EventHandler(CheckOut_Click);
TableCell firstCell = new TableCell();
firstCell.Controls.Add(userId);
TableCell secondCell = new TableCell();
secondCell.Controls.Add(checkOut);
BookCopyStatusNode.Controls.Add(firstCell);
BookCopyStatusNode.Controls.Add(secondCell);
}
private void CreateReturnControls()
{
Label userMessage = new Label();
userMessage.Text = empName + " has this book checked out.";
Button returnButton = new Button();
returnButton.Text = "Return it";
returnButton.Click += new EventHandler(ReturnButton_Click);
TableCell firstCell = new TableCell();
firstCell.Controls.Add(userMessage);
TableCell secondCell = new TableCell();
secondCell.Controls.Add(returnButton);
BookCopyStatusNode.Controls.Add(firstCell);
BookCopyStatusNode.Controls.Add(secondCell);
}
It looks like you're creating a static set of controls based on the database value. Why not simply have 2 Panels that contain the controls you want and simply set their visibility to true or false:
if (!Page.IsPostBack)
{
if (int.TryParse(Request.QueryString["id"], out bookId))
{
empName = Book.GetCopyOwner(bookId, Request.QueryString["owner"]);
var display = (empName.Trim().Length > 0);
panelReturnControls.Visible = display;
panelCheckoutControls.Visible = !display;
}
}

Categories

Resources