how to get the value of dynamically populated controls - c#

I have a div Conatining a Panel in aspx page
<div id="divNameofParticipants" runat="server">
<asp:Panel ID="panelNameofParticipants" runat="server">
</asp:Panel>
</div>
I am populating the panel dynamically from codebehind with the following code:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
panelNameofParticipants.Controls.Add(tableparticipantName);
}
}
catch(Exception ex)
{
}
}
Now I want to access the value of these dynamically generated textbox in the codebehind.for which i my code is as under:
public void CreateControls()
{
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
}
}
catch (Exception ex)
{
}
}
but I am not able to get the values in codebehind.
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
the above code is not able to find the control and its always giving null.what am i doing wrong.i recreated the controls in page load also since postback is stateless but still no success.
Thanks in Advance

You need to create dynamic controls in PreInit not in OnLoad. See documentation here: https://msdn.microsoft.com/en-us/library/ms178472.aspx
Re/Creating the controls on page load will cause the ViewState not to be bound to the controls because viewstate binding happens before OnLoad.

As mentioned by other people. To create dynamic controls your need to do this for every postback and at the right time. To render dynamic controls, use the Preinit event. I suggest that your have a look at https://msdn.microsoft.com/en-us/library/ms178472(v=vs.80).aspx to learn more about this.
MSDN - PreInit:
Use this event for the following:
Check the IsPostBack property to determine whether this is the first time the page is being processed.
Create or re-create dynamic controls.
Set a master page dynamically.
Set the Theme property dynamically.
Read or set profile property values.
NoteNote If the request is a postback, the values of the controls have not yet been restored from view state. If you set a control property at this stage, its value might be overwritten in the next event.
The next interesting event is Preload that states:
MSDN - PreLoad
Use this event if you need to perform processing on your page or control before the Load event.
After the Page raises this event, it loads view state for itself and all controls, and then processes any postback data included with the Request instance.
Meaning that in the next event Load (Page_Load) the viewstate should be loaded, so here you should effectively be able to check your values.
You also need to make sure that view state is enabled and the easiest is probably in the page level directive:
<%#Page EnableViewState="True" %>
Take a look at the article https://msdn.microsoft.com/en-us/library/ms972976.aspx2 that goes more into the depth of all this
Note
If your problem is that you need to create controls dynamically on a button click, and there will be many controls created, you should probably turn to jQuery ajax and use the attribute [WebMethod] on a public function in your code behind. Creating dynamic controls and maintaining the ViewState is quite costly, so i really recommend this, for a better user experience.

If you use a DataPresentation control like asp:GridView it will be much easier.
Markup
<asp:GridView ID="ParticipantsGrid" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Participants">
<ItemTemplate>
<asp:TextBox ID="txtNameofParticipant" runat="server"
Text='<%# Container.DataItem %>'>
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code-behind
protected void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
try
{
var selectedParticipantCount = Convert.ToInt32(drpNoofparticipants.SelectedValue);
var items = Enumerable.Repeat(string.Empty, selectedParticipantCount).ToList();
ParticipantsGrid.DataSource = items;
ParticipantsGrid.DataBind();
}
catch (Exception ex)
{ }
}
public void CreateControls()
{
try
{
var participants = ParticipantsGrid.Rows
.Cast<GridViewRow>()
.Select(row => ((TextBox)row.FindControl("txtNameofParticipant")).Text)
.ToList();
}
catch (Exception ex)
{ }
}

I think you are doing that correctly. In asp.net webforms, there are lots of times that you will experienced strange things that are happening. Especially with the presence of ViewState. First we need to troubleshoot our code and try different tests and approaches. That will be my advise for you, pleas use this code and debug if what is really happening:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
TableRow row = new TableRow();
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "NameTest";
txtNameofParticipant.Text = "This is a textbox";
cell.ID = "cellTest";
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
tableparticipantName.Rows.Add(row);
panelNameofParticipants.Controls.Add(tableparticipantName);
}
catch(Exception ex)
{ // please put a breakpoint here, so that we'll know if something occurs,
}
}
public void CreateControls()
{
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
//if (ViewState["numberofparticipants"] != null)
//{
string findcontrol = "NameTest";
TextBox txtParticipantName = (TextBox)panelNameofParticipants.Controls["NameText"];
//check if get what we want.
listParticipantName.Add(txtParticipantName.Text);
//}
}
catch (Exception ex)
{// please put a breakpoint here, so that we'll know if something occurs,
}
}

Dynamic controls need to be recreated on every post-back. The easiest way to achieve that in your code would be to cache the control structure and repopulate it. This how it can be done:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
Panel p1 = new Panel();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
p1.Controls.Add(tableparticipantName);
}
Cache["TempPanel"] = p1;
panelNameofParticipants.Controls.Add(p1);
}
catch(Exception ex)
{
}
}
Look for the p1 panel in the above code to see the changes. Now the code for the CreateControls function need to be changed as following:
public void CreateControls()
{
try
{
Panel p1= (Panel)Cache["TempPanel"];
panelNameofParticipants.Controls.Add(p1);
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
}
}
catch (Exception ex)
{
}
}
Hope this helps.

Dynamically created controls would disappear when page posts back, This article here explains why it happens.
So in order to make dynamic controls be recognized by asp.net page, you need to recreate it in preinit event handler, but I think it is difficult as this dynamic controls in your case rely on some other web form element such as a dropdownlist drpNoofparticipants and also ViewState is not available at this stage.
My suggestion is that we do it in a different way, each post back is actually a form post, so instead of finding the dynamic text box, you could directly get the value via Request.Form collection. Here is the code snippet:
var list = Request.Form.AllKeys.Where(x => x.Contains("txtNameofParticipant"));
foreach (var item in list)
{
var value = Request.Form[item];
}
In this way, you could get the value and since you don't need to rely on ASP.NET engine to retrieve the value from dynamically created control, you could postpone the recreating the table in page_load event handler.
Hope it helps.

Put your btnSubmitCountParticipant_Click method data into other function with name of your choice. Call that function in method btnSubmitCountParticipant_Click and in method CreateControls(). Also cut paste the below code in btnSubmitCountParticipant_Click method
int numberofparticipants =
Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
. This is working in my machine. Hope this helps

Yes,Dynamic controls are lost in postback,So we need save dynamic control values in Viewsate and again generate dynamic control.I added code here, this working fine
//Create Button Dynamic Control
protected void btnDyCreateControl_Click(object sender, EventArgs e)
{
try
{
int numberofparticipants = 5;
ViewState["numberofparticipants"] = numberofparticipants;
int test = (int)ViewState["numberofparticipants"];
int rowcount = 1;
int columnCount = numberofparticipants;
CreateDynamicTable(rowcount, columnCount);
}
catch (Exception ex)
{
}
}
//submit values
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
int i = 0;
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)cell.Controls[0].FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
i++;
}
}
}
}
}
}
catch (Exception ex)
{
}
}
//Save ViewState
protected override object SaveViewState()
{
object[] newViewState = new object[3];
List<string> txtValues = new List<string>();
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox)
{
txtValues.Add(((TextBox)cell.Controls[0]).Text);
}
}
}
}
}
newViewState[0] = txtValues.ToArray();
newViewState[1] = base.SaveViewState();
if (ViewState["numberofparticipants"] != null)
newViewState[2] = (int)ViewState["numberofparticipants"];
else
newViewState[2] = 0;
return newViewState;
}
//Load ViewState
protected override void LoadViewState(object savedState)
{
//if we can identify the custom view state as defined in the override for SaveViewState
if (savedState is object[] && ((object[])savedState).Length == 3 && ((object[])savedState)[0] is string[])
{
object[] newViewState = (object[])savedState;
string[] txtValues = (string[])(newViewState[0]);
if (txtValues.Length > 0)
{
//re-load tables
CreateDynamicTable(1, Convert.ToInt32(newViewState[2]));
int i = 0;
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox && i < txtValues.Length)
{
((TextBox)cell.Controls[0]).Text = txtValues[i++].ToString();
}
}
}
}
}
}
//load the ViewState normally
base.LoadViewState(newViewState[1]);
}
else
{
base.LoadViewState(savedState);
}
}
//Create Dynamic Control
public void CreateDynamicTable(int rowcount, int columnCount)
{
Table tableparticipantName = new Table();
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
cell.ID = "cell" + Convert.ToString(j);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
tableparticipantName.EnableViewState = true;
ViewState["tableparticipantName"] = true;
}
panelNameofParticipants.Controls.Add(tableparticipantName);
}
Reference Link,MSDN Link, Hope it helps.

When creating your textboxes make sure you set the ClientIDMode
I recently worked on something similar. I dynamically created checkboxes in GridView rows and it worked for me.
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
txtNameOfParticipant.ClientIDMode = System.Web.UI.ClientIDMode.Static;

Dynamically added controls have to be created again on postback, otherwise the state of the dynamically added controls will get lost (if the controls lost how can one preserve their old state) . Now the question. When is the viewstated loaded? It is loaded in between the two events Page_Init and Load.
Following code samples are a bit modification of your code for your understanding
The aspx markup is same as yours, but with some extra controls
<form id="form1" runat="server">
<asp:DropDownList ID="drpNoofparticipants" runat="server" >
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
<asp:ListItem>3</asp:ListItem>
<asp:ListItem>4</asp:ListItem>
<asp:ListItem>5</asp:ListItem>
<asp:ListItem>6</asp:ListItem>
<asp:ListItem>7</asp:ListItem>
<asp:ListItem>8</asp:ListItem>
<asp:ListItem>9</asp:ListItem>
<asp:ListItem>10</asp:ListItem>
</asp:DropDownList>
<br /><asp:Button ID="btnCreateTextBoxes" runat="server" OnClick="btnSubmitCountParticipant_Click" Text="Create TextBoxes" />
<div id="divNameofParticipants" runat="server">
<asp:Panel ID="panelNameofParticipants" runat="server">
</asp:Panel>
</div>
<div>
<asp:Button ID="btnSubmitParticipants" runat="server" Text="Submit the Participants" OnClick="BtnSubmitParticipantsClicked" />
</div>
</form>
On click event of the btnCreateTextBoxes button i am creating the controls using the following code
private void CreateTheControlsAgain(int numberofparticipants)
{
try
{
ViewState["numberofparticipants"] = Convert.ToString(numberofparticipants);
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
for (int j = 0; j < columnCount; j++)
{
TableRow row = new TableRow();
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
cell.ID = "cell" + Convert.ToString(j);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
tableparticipantName.Rows.Add(row);
}
}
panelNameofParticipants.Controls.Add(tableparticipantName);
}
catch (Exception ex)
{
}
}
As mentioned above to maintain the control state, i included the re-creation of the controls in the page Load event based on the viewstate["numberofparticipants"]
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["numberofparticipants"] != null)
{
CreateTheControlsAgain(Convert.ToInt32(ViewState["numberofparticipants"]));
CreateControls();
}
}
On click event of btnSubmitParticipants button i wrote the following event and writing the participants names to the console
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
var txtParticipantName = panelNameofParticipants.FindControl(string.Format("txtNameofParticipant{0}", i)) as TextBox;
listParticipantName.Add(txtParticipantName.Text);
}
}
foreach (var item in listParticipantName)
{
Response.Write(string.Format("{0}<br/>", item));
}
}
catch (Exception ex)
{
}
Hope this helps

I'm not sure if this is desired, but you're adding multiple tables to your panel, but I think you only want/need one table. So this line should be outside the outer for loop like so:
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
}
panelNameofParticipants.Controls.Add(tableparticipantName);
Additionally, FindControl will only search the direct children of the container, in this case it can only find the table, else it'll return null. so you need to search children of the panel to find the control, e.g. your table:
foreach (TableRow row in tableparticipantName.Rows)
{
TextBox txtParticipantName = (TextBox)row.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
If that doesn't work then doing it recursively might work better:
ASP.NET Is there a better way to find controls that are within other controls?

Related

C# Error when searching for control in UpdatePanel

I have a little problem. First of all, some info:
- On my page, I have an UpdatePanel with a button inside it.
- When you click this button, I generate a new row with dropdown lists. Each time I have to generate a table from scratch, because it resets after the click, so I update [ViewState] value and generate as many rows as clicks.
- Outside the panel, I have another button. After clicking this button, I want to collect data from drop-down lists. To do it, I have to get to these controls.
I tried to use function FindControl(), but I guess I can't - as far as I know, it does not perform a deep search. This means I have to pass as a parameter the exact container with this control. Because control is inside the table, I should get to the <td> value and I can't do that (<td> does not have ID - yes, I can add it but <td> is also dynamically created. That means I would need to get first to <td>, then to my control (guess what - <tr> is also created dynamically).
Because I can't use FindControl function, I use FindRecursiveControl function (code below) The problem is, that this function neither finds anything. Any suggestions about what might be the reason? I added this whole info in case that the reason is for example usage of UpdatePanel and page life cycle.
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID)
{
return rootControl;
}
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null)
{
return controlToReturn;
}
}
return null;
}
My usage of this function:
string control_id = "parametr" + i;
DropDownList dropdown = (DropDownList)FindControlRecursive(UpdatePanel1, control_id);
Script generating table in UpdatePanel after button click
protected void generuj_tabele(int il_klik)
{
il_par.Text = "Ilość parametrów: " + il_klik.ToString();
TableRow table_head = new TableRow();
table_head.Attributes.Add("class", "w3-green");
Table1.Rows.Add(table_head);
for (int j = 0; j < 5; j++)
{
TableCell cell = new TableCell();
table_head.Cells.Add(cell);
}
Table1.Rows[0].Cells[0].Text = "Parametr";
Table1.Rows[0].Cells[1].Text = "Wartość początkowa";
Table1.Rows[0].Cells[2].Text = "Inkrementacja?";
Table1.Rows[0].Cells[3].Text = "Zwiększ o:";
Table1.Rows[0].Cells[4].Text = "Zwiększ co:";
RootObject obj = (RootObject)Session["get_offer"];
for (int i = 0; i < il_klik; i++)
{
parametr = new DropDownList();
wartosc = new TextBox();
inkrementacja = new CheckBox();
inkrementacja_numer = new TextBox();
skok = new TextBox();
//inkrementacja_numer.Enabled = false;
// skok.Enabled = false;
inkrementacja_numer.Attributes.Add("Type", "number");
skok.Attributes.Add("Type", "number");
//inkrementacja.CheckedChanged += new EventHandler((s, eventarg) => checkbox_change(s, eventarg, i));
//inkrementacja.AutoPostBack = true;
//parametr.AutoPostBack = true;
TableRow row = new TableRow();
Table1.Rows.Add(row);
parametr.EnableViewState = true;
wartosc.EnableViewState = true;
inkrementacja.EnableViewState = true;
inkrementacja_numer.EnableViewState = true;
skok.EnableViewState = true;
for (int j = 0; j < 5; j++)
{
TableCell cell = new TableCell();
row.Cells.Add(cell);
}
Table1.Rows[i + 1].Cells[0].Controls.Add(parametr);
Table1.Rows[i + 1].Cells[1].Controls.Add(wartosc);
Table1.Rows[i + 1].Cells[2].Controls.Add(inkrementacja);
Table1.Rows[i + 1].Cells[3].Controls.Add(inkrementacja_numer);
Table1.Rows[i + 1].Cells[4].Controls.Add(skok);
if (i == il_klik - 1)
{
wystaw_liste(obj);
Price pr = obj.sellingMode.price;
parametr.Items.Add(pr.amount.ToString());
List<Parameter> par = obj.parameters;
foreach (Parameter p in par)
{
List<string> val = p.values;
if (val.Count() > 0)
{
foreach (string v in val)
{
parametr.Items.Add(v);
}
}
}
foreach (string p in parametry_list)
{
parametr.Items.Add(p);
}
parametry_list.Clear();
}
parametry.Add(parametr);
wartosci.Add(wartosc);
inkrementacje.Add(inkrementacja);
inkrementacje_numery.Add(inkrementacja_numer);
skoki.Add(skok);
if (i == il_klik - 1)
{
Session["v_parametr"] = parametry;
Session["v_wartosc"] = wartosci;
Session["v_inkrementacja"] = inkrementacje;
Session["v_ink_nr"] = inkrementacje_numery;
Session["v_skok"] = skoki;
}
parametr.ID = "parametr" + i;
wartosc.ID = "wartosc" + i;
inkrementacja.ID = "inkrementacja" + i;
inkrementacja_numer.ID = "inkrementacja_numer" + i;
skok.ID = "skok" + i;
}
}
When I try to check parameters of DropDownList (e.g. SelectedValue) I get error "Object reference not set to an instance of an object"

.Net Wizard user inputs being overwritten

I have been searching quite a bit, but unable to find something that addresses the issue I am seeing. I am sure I am missing something simple, but I have been fighting it too long, and really need to figure out what is going on. I have an existing (working) user control that I am rebuilding. It is a multi-step wizard, with each step being a type of "form" created from tables. I have successfully converted 3 of the 4 steps to divs to make them dynamic (using Bootstrap 3), but this one step, step 2, is not working like the rest. The user's input is being lost. The original code (table based) works properly. It is a simple table declared on the .ascx side:
<asp:WizardStep ID="childInformationStep" runat="server" Title="">
<%-- Some more stuff...--%>
<asp:Table cellpadding="2" class="annualSurveyTable" cellspacing="0" border="0" ID="tblChildInfo" runat="server">
</asp:Table>
<asp:WizardStep>
On the c# side, during Page_Load, a method is called to cycle through all the children of a family and dynamically build rows with pre-populated input cells for each child's First/Last Name, B-day, gender and grade. It looks like this:
private void AddChildEdit(Person child, int index)
{
TableRow row = new TableRow();
TableCell cell = new TableCell();
row.ID = "trChildFirstName_" + index;
cell.ID = "tcChildFirstName_" + index;
cell.VerticalAlign = VerticalAlign.Middle;
cell.HorizontalAlign = HorizontalAlign.Right;
cell.Wrap = false;
cell.CssClass = "registrationLabel";
cell.Text = "Child's First Name";
row.Cells.Add(cell);
cell = new TableCell();
TextBox tb = new TextBox();
tb.ID = "tbChildFirstName_" + index;
tb.Text = child.FirstName;
tb.Enabled = false;
cell.Controls.Add(tb);
row.Cells.Add(cell);
tblChildInfo.Rows.AddAt(tblChildInfo.Rows.Count, row);
// snip (more of same for last name)
row = new TableRow();
cell = new TableCell();
row.ID = "trChildBirthday_" + index;
cell.ID = "tcChildBirthday_" + index;
cell.VerticalAlign = VerticalAlign.Middle;
cell.HorizontalAlign = HorizontalAlign.Right;
cell.Wrap = false;
cell.CssClass = "registrationLabel Birthday";
cell.Text = "Child's Birth Date";
row.Cells.Add(cell);
cell = new TableCell();
DateTextBox dtb = new DateTextBox();
dtb.ID = "tbChildBirthday_" + index;
dtb.CssClass = "registrationItem Birthday";
if (child.BirthDate != DateTime.MinValue && child.BirthDate != DateTime.Parse("1/1/1900"))
dtb.Text = child.BirthDate.ToShortDateString();
cell.Controls.Add(dtb);
row.Cells.Add(cell);
tblChildInfo.Rows.AddAt(tblChildInfo.Rows.Count, row);
row = new TableRow();
cell = new TableCell();
row.ID = "trChildGender_" + index;
cell.ID = "tcChildGender_" + index;
cell.VerticalAlign = VerticalAlign.Middle;
cell.HorizontalAlign = HorizontalAlign.Right;
cell.Wrap = false;
cell.CssClass = "registrationLabel";
cell.Text = "Child's Gender";
row.Cells.Add(cell);
cell = new TableCell();
DropDownList ddlGender = new DropDownList();
ListItem l = new ListItem("", "", true);
l.Selected = true;
ddlGender.Items.Add(l);
l = new ListItem("Male", "0", true);
ddlGender.Items.Add(l);
l = new ListItem("Female", "1", true);
ddlGender.Items.Add(l);
ddlGender.ID = "ddlChildGender_" + index;
// snip (there is one more row added for grade
}
And the save method looks like it cycles through the table looking for the inputs related to the children it is looping through, and pulling in the text value, which should include any changes the user has made. It works as desired, and looks like this (BTW, I didn't write it, it looks like it could be cleaned up quite a bit :D)
private void SaveChildValues()
{
string userID = CurrentUser.Identity.Name + " - Annual Survey";
if (userID == " - Annual Survey")
userID = "Annual Survey";
int i = 0;
foreach (Person child in childrenList)
{
TableCell selectedCell = null;
foreach (TableRow row in tblChildInfo.Rows)
{
if (row.ID == "trChildBirthday_" + i)
{
foreach (TableCell cell in row.Cells)
{
if (cell.ID == "tcChildBirthday_" + i)
{
selectedCell = cell;
DateTextBox box = (DateTextBox)selectedCell.FindControl("tbChildBirthday_" + i);
if (box.Text.Trim() != string.Empty)
try { child.BirthDate = DateTime.Parse(box.Text); }
catch { }
i++;
break;
}
}
break;
}
}
}
i = 0;
foreach (Person child in childrenList)
{
TableCell selectedCell = null;
foreach (TableRow row in tblChildInfo.Rows)
{
if (row.ID == "trChildGender_" + i)
{
foreach (TableCell cell in row.Cells)
{
if (cell.ID == "tcChildGender_" + i)
{
selectedCell = cell;
DropDownList ddl = (DropDownList)selectedCell.FindControl("ddlChildGender_" + i);
if (ddl.SelectedValue != string.Empty)
try { child.Gender = (Gender)Enum.Parse(typeof(Gender), ddl.SelectedValue); }
catch { }
i++;
break;
}
}
break;
}
}
}
i = 0;
foreach (Person child in childrenList)
{
TableCell selectedCell = null;
foreach (TableRow row in tblChildInfo.Rows)
{
if (row.ID == "trChildGrade_" + i)
{
foreach (TableCell cell in row.Cells)
{
if (cell.ID == "tcChildGrade_" + i)
{
selectedCell = cell;
DropDownList ddl = (DropDownList)selectedCell.FindControl("ddlChildGrade_" + i);
if (ddl.SelectedValue != string.Empty)
try { child.GraduationDate = Person.CalculateGraduationYear(Int32.Parse(ddl.SelectedValue), CurrentOrganization.GradePromotionDate); }
catch { }
i++;
break;
}
}
break;
}
}
}
}
Now, here are the changes that I have made to that section. The page loads, and runs through all the motions, yet when the save happens, it is pulling in the original DB value from the child record again instead of the user's input. I simply changed the table to an ASP Panel in the .ascx file:
<asp:WizardStep ID="childInformationStep" runat="server" Title="">
<%-- Some more stuff...--%>
<asp:Panel ID="tblChildInfo" runat="server" ClientIDMode="Static">
</asp:Panel>
<asp:WizardStep>
I have changed the dynamic row creation to dynamic divs, laid out for bootstrap 3:
private void AddChildEdit(Person child, int index)
{
Panel childRow = new Panel();
childRow.ID = "ChildRow_" + index;
childRow.CssClass = "form-horizontal";
LiteralControl childTitle = new LiteralControl();
childTitle.Text = string.Format("<h4>Child {0}:</h4>", (index + 1).ToString());
childRow.Controls.Add(childTitle);
Panel formGroup = new Panel();
formGroup.ID = "trChildFirstName_" + index;
formGroup.CssClass = "form-group";
childRow.Controls.Add(formGroup);
Panel inputContainer = new Panel();
inputContainer.CssClass = "col-sm-8";
formGroup.Controls.Add(inputContainer);
TextBox tb = new TextBox();
tb.ID = "tbChildFirstName_" + index;
tb.Text = child.FirstName;
tb.Enabled = false;
inputContainer.Controls.Add(tb);
Label inputLabel = new Label();
inputLabel.ID = "tcChildFirstName_" + index;
inputLabel.CssClass = "col-sm-3 control-label registrationLabel";
inputLabel.Text = "First Name";
inputLabel.AssociatedControlID = tb.ID;
formGroup.Controls.AddAt(0, inputLabel);
tblChildInfo.Controls.Add(childRow);
// snip (more code for adding Last Name row
formGroup = new Panel();
formGroup.ID = "trChildBirthday_" + index;
formGroup.CssClass = "form-group";
inputContainer = new Panel();
inputContainer.ID = "tcChildBirthday_" + index;
inputContainer.CssClass = "col-sm-8";
formGroup.Controls.Add(inputContainer);
TextBox dtb = new TextBox();
dtb.ID = "tbChildBirthday_" + index;
dtb.CssClass = "form-control survey-control date-mask registrationItem";
dtb.Attributes.Add("placeholder", "MM/DD/YYYY");
if (child.BirthDate != DateTime.MinValue && child.BirthDate != DateTime.Parse("1/1/1900"))
dtb.Text = child.BirthDate.ToString("MM/dd/yyyy");
inputContainer.Controls.Add(dtb);
inputLabel = new Label();
inputLabel.CssClass = "col-sm-3 control-label";
inputLabel.Text = "BirthDate";
inputLabel.AssociatedControlID = dtb.ID;
formGroup.Controls.AddAt(0, inputLabel);
childRow.Controls.Add(formGroup);
// snip (more of the same, adding two more rows for gender and grade)
}
And I simplified the save method to:
private void SaveChildValues()
{
string userID = CurrentUser.Identity.Name + " - Annual Survey";
if (userID == " - Annual Survey")
userID = "Annual Survey";
int i = 0;
foreach (Person child in childrenList)
{
try
{
TextBox box = (TextBox)tblChildInfo.FindControl("tbChildBirthday_" + i);
if (box.Text.Trim() != string.Empty)
child.BirthDate = DateTime.Parse(box.Text);
}
catch { }
try
{
DropDownList ddl = (DropDownList)tblChildInfo.FindControl("ddlChildGender_" + i);
if (ddl.SelectedValue != string.Empty)
child.Gender = (Gender)Enum.Parse(typeof(Gender), ddl.SelectedValue);
}
catch {}
try
{
DropDownList ddl = (DropDownList)tblChildInfo.FindControl("ddlChildGrade_" + i);
if (ddl.SelectedValue != string.Empty)
child.GraduationDate = Person.CalculateGraduationYear(Int32.Parse(ddl.SelectedValue), CurrentOrganization.GradePromotionDate);
}
catch { }
i++;
}
As far as I understand it, my code does not change any fundamental behavior, other than it is using div elements to build out the dynamic content rather then adding rows to a table. What am I missing that is causing my updated code to lose the users' input?
NOTE: this is step two, where the information is rendered, captured for the child info. The save method is not executed until step 4, so the input data should be persisting through two more steps, and remain in tact. I have tried using debugger, but can never see the users input. I don't know if I am looking for it at the wrong breakpoints, but I can't seem to find where the user input is coming back with the post, and when it SHOULD be getting written to the inputs. Any help would be greatly appreciated.
You could try moving the dynamic creation of the fields into the Page_Init section rather than the Page_Load.

How to read from a GridView

Solution, for at least a specific cell: GridView1.Rows[i].Cells[j].Text;
I've build a simple CSV-Fileupload. After the user uploaded the file he should be able to evaluate the data. When the fileupload was successful the data gets loaded into the GridView1, with this code: (Problem below the code)
string[] readCSV = File.ReadAllLines(lblFilePath.Text);
DataTable dt = new DataTable();
bool bSplitMe = false;
foreach (var rLine in readCSV)
{
if (bSplitMe)
{
string[] aSplittedLine = rLine.Split(";".ToCharArray());
try
{
dt.Rows.Add(aSplittedLine);
}
catch(System.Exception)
{
txtBoxFileOut.Text = rLine;
break;
}
}
else
{
if (rLine.ToLower().StartsWith("definedtestid;"))
{
bSplitMe = true;
string[] aSplittedLine = rLine.Split(";".ToCharArray());
foreach (var rCol in aSplittedLine)
{
dt.Columns.Add(rCol);
}
}
else
{
txtBoxFileOut.Text += rLine.ToString() + "\n";
}
}
}
dt.Columns.Remove("Column1");
for (int i = 0; i < dt.Rows.Count; i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
if (string.IsNullOrEmpty(dt.Rows[i][j].ToString()))
{
dt.Rows[i][j] = "0";
}
}
}
GridView1.DataSource = dt;
GridView1.DataBind();
After this the user should be able to select a row and display the data from that row in a chart.
Problem: I'm not able to read data from the cells I want, or to read from a "hardcoded" cell.
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e) {
GridViewRow row = GridView1.SelectedRow;
txtOutputfield.Text = row.Cells[2].Text;
}
Please check your cell index. Is it correct? For example: the third column will have index "2" not "3"
And, if you use a control to store the data, you need to find that control:
txtOutputfield.Text =
row.Cells[2].FindControl('placeyourcontrolnamehere').Text;
For a specific Cell this worked fine
txtOutputfield.Text = GridView1.Rows[i].Cells[j].Text;

ASP.NET loop through datatable column and write a checkbox for each item

I'm brand new to ASP.NET with intermediate C# level, and previously I wrote a PHP project. I'm now stuck trying to get a similar effect in ASP.NET.
What I'm using:
The project is C# ASP.NET Empty web application. I'm using Visual Studio 2010 with SP1.
MSSQL 2008 R2
What I want to do is add HTML code using a foreach into the ASP file, specific content area.
This is what I would do in php:
foreach ($library as $book)
{
print "<a href=\"bookpage.php?id=".$book[book_id]"";
print "<h3>".$book[book_author]."</h3>";
print " <p>".$book[book_blurb]."</p>";
}
This is what I've tried in ASP:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:RadioButtonList ID="RadioButtonPizzaList" runat="server">
<asp:ListItem Text="Margerita" />
<asp:ListItem Text="Hawaain" />
<asp:ListItem Text="Meat Supreme" />
</asp:RadioButtonList>
</asp:Content>
But instead of hardcoding, I want to add a listitem for each pizza thats been retrieved from the database, the names of pizza are stored in an array. How would I use a loop and add an HTML line like what I did in above PHP example?
I assume that your pizza list has two columns that Id and PizzaName.
And you have a method that getting pizza list from db as named GetList in Pizza class.
Firstly you should add two attributes in aspx side to your radio button list control.
They are DataValueField and DataTextField.
These attributes required for data binding.
Aspx Side
<asp:RadioButtonList ID="RadioButtonPizzaList" DataValueField="Id" DataTextField="PizzaName" runat="server">
</asp:RadioButtonList>
Code behind Side
private void FillPizzaList()
{
DataTable dtList = Pizza.GetList();
this.RadioButtonPizzaList.DataSource = dtList;
this.RadioButtonPizzaList.DataBind();
}
If you want to get selected item value you can get with this code
this.RadioButtonPizzaList.SelectedValue
Note: If you fill radiobutton list in page load event, do not forget check is postback.
if ( !IsPostBack )
this.FillPizzaList();
In the end, the answer to my problem was using c# to create the table and add rows, and in the cells add the content. One of the questions around here while I was looking around was kind of answered, but not fully. So if you see this you can adapt it.
I've changed from using checkboxes to simply adding text to the cell area, but to answer my original question, one can do what I did with the textboxes and choose which cells to add the checkboxes, or simply do without the table and loop checkboxes into your wanted area.
At the end I add the table to a div that is ready made in the asp code
public partial class _Default : System.Web.UI.Page
{
Database doDatabase = new Database();//custom class for querying a database
ArrayList textboxNames = new ArrayList();//just to make life easier
ArrayList pizzaNames = new ArrayList();//just to make life easier
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
this.FillPizzaList();
}
private void FillPizzaList()
{
int count = 1;
string query = "select FoodID, FoodName, 'R' + Convert(char(10), FoodPrice)[Food Price], rtrim(FoodDesc)[FoodDesc] from tblFood";
doDatabase.Do_SQLQuery(query);
Table tablePizza = new Table();
TableRow tr = new TableRow();
TableCell tc = new TableCell();
for (int c = 0; c < 4; c++)
{
tc = new TableCell();
if (c == 0)
{
tc.Width = new Unit("15%");
tc.Text = "<h3>Pizza Name</h3>";
}
else if (c == 1)
{
tc.Text = "<h3>Pizza Description</h3>";
}
else if (c == 2)
{
tc.HorizontalAlign = HorizontalAlign.Center;
tc.Width = new Unit("15%");
tc.Text = "<h3>Pizza Price</h3>";
}
else if (c == 3)
{
tc.Width = new Unit("12%");
tc.Text = "<h3>Pizza Quantity</h3>";
}
tr.Cells.Add(tc);
}
tablePizza.Rows.Add(tr);
foreach (DataRow dr in doDatabase.dataTbl.Rows)
{
tr = new TableRow();
for (int c = 0; c < 4; c++)
{
tc = new TableCell();
if (c == 0)
{
pizzaNames.Add(dr["FoodName"].ToString());
tc.Text = dr["FoodName"].ToString();
}
else if (c == 1)
{
tc.Text = dr["FoodDesc"].ToString();
}
else if (c == 2)
{
tc.HorizontalAlign = HorizontalAlign.Center;
tc.Text = dr["Food Price"].ToString();
}
else if (c == 3)
{
TextBox MyTextBox = new TextBox();
MyTextBox.ID = "Quantity" + count;
textboxNames.Add("Quantity" + count);
MyTextBox.Text = "0";
tc.Controls.Add(MyTextBox);
count++;
}
tr.Cells.Add(tc);
}
tablePizza.Rows.Add(tr);
}
pizzaMenu.Controls.Add(tablePizza);//add table to div
}

Tag Array c# winforms

The code below lets me show emails received in a listview on when the selected index is changed displays the body of the selected email in a RTB. The problem is i changed the code to work with a data grid view and now the Tag part wont work
void SomeFunc() // This line added by Jon
{
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
ListViewItem itmp = new ListViewItem(email.From);
ListViewItem.ListViewSubItem itms1 =
new ListViewItem.ListViewSubItem(itmp, email.Subject);
ListViewItem.ListViewSubItem itms2 =
new ListViewItem.ListViewSubItem(itmp, email.FromName);
itmp.SubItems.Add(itms1);
itmp.SubItems.Add(itms2);
listView1.Items.Add(itmp).Tag = i;
richTextBox1.Text = email.Body;
}
// Save the email to an XML file
bundle.SaveXml("email.xml");
}
private void listView1_SelectionChanged(object sender, EventArgs e)
{
if (listView1.SelectedCells.Count > 0)
{
// bundle is now accessible in your event handler:
richTextBox1.Text = bundle.GetEmail((int)listView1.SelectedCells[0].Tag).Body;
}
}
Code for data grid view
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
string[] row = new string[] { email.From, email.Subject, email.FromName };
object[] rows = new object[] { row };
foreach (string[] rowArray in rows)
{
dataGridView1.Rows.Add(rowArray);
}
} // This line added by Jon
i have created earlier the code for datagrid view but you already done it so i haven't posted in your last question but i think , you should give a try to the below code.
// i am creating a new object here but , you can have a single object on the form
DataGridView dgv = new DataGridView();
private DataTable EmailSource { get; set; }
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgv.SelectionChanged+=new EventHandler(dgv_SelectionChanged);
Chilkat.MessageSet msgSet = imap.Search("ALL", true);
if (msgSet != null)
{
bundle = imap.FetchBundle(msgSet);
CreateDataTable();
if (bundle != null && dt!=null)
{
Chilkat.Email email;
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
if(email!=null)
{
DataRow drow = EmailSource.NewRow();
drow["Id"] = i.ToString();
drow["From"] = email.FromName;
drow["Subject"] = email.Subject;
drow["DateRecived"] = email.DateRecived;
// i am adding email body also
drow["Body"] =email.Body;
EmailSource.Rows.Add(drow);
}
}
// Save the email to an XML file
bundle.SaveXml("email.xml");
dgv.DataSource= EmailSource;
// Hiding Body from the grid
dgv.Columns["Body"].Visible =false;
}
}
// this event handler will show the last selected email.
void dgv_SelectionChanged(object sender, EventArgs e)
{
DataGridViewSelectedRowCollection rows = dgv.SelectedRows;
if (rows != null)
{
// get the last selected row
DataRow drow = rows[rows.Count - 1].DataBoundItem as DataRow;
if (drow != null)
{
richTextBox1.Text = drow["Body"];
}
}
}
private void CreateDataTable()
{
EmailSource = new DataTable();
EmailSource.Columns.Add("Id");
EmailSource.Columns.Add("From");
EmailSource.Columns.Add("Subject");
EmailSource.Columns.Add("DateRecived");
EmailSource.Columns.Add("Body");
}
You are adding rows using listView1.Rows.Add(rowArray) in both the code listings. Is that a typo or you named the GridView like that.
Basically, you are storing the index of the email in the "Tag" property.
listView1.Items.Add(itmp).Tag = i;
You need to make sure that you do the same while adding items to the GridView too.
The DataGridView does not have an "Items" collection. To make it work, you need to bind the DataGridView to a collection of objects. Something like this should get you started:
List<Email> emails = new List<Email>();
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
emails.Add(email);
}
dataGridView.ItemsSource = emails;
You should not need to store the row index for each item in a "Tag" object - you can can get the selected index like this:
int selectedIndex = dataGridView.SelectedCells[0].RowIndex;

Categories