I have this data in same sql table. I need to create a tree look like structure for the following data. Everything seems to be working fine except the indenting is not working right. I am missing something minor which I am not able to figure out. I will appreciate any help.
This is data in same table
initiated_by
---------------------
NULL,42521,42521,41651,41111,41111,41131,41651
user_id (assigned to)
---------------------
42521,41651,42681,41111,42021,41131,42001,43001
What I expecting is as follow.
42521 (at level 0)
41651 (at level 1)
41111 (at level 2)
42021(at level 3)
41131(at level 3)
42001(at level 4)
43001(at level 2)
42681 (at level 1)
But what I am getting is not right. I am not able to figure out the indentLevel part. indentLevel is a variable declared at class level.
private void BuildTable(DataTable recordList)
{
foreach (DataRow dr in recordList.Rows)
{
TableRow tblRow = new TableRow();
TableCell tblCell = new TableCell();
tblCell.Controls.Add(GetDetailTable(dr, indentLevel));
tblCell.HorizontalAlign = HorizontalAlign.Left;
tblRow.Cells.Add(tblCell);
mainTable.Rows.Add(tblRow);
//Do we have any child objects
int cId = Convert.ToInt32(dr["user_id"].ToString());
DataTable dt = GetChildObjects(Convert.ToInt32(dr["user_id"].ToString()), masterDT);
if (dt.Rows.Count > 0) indentLevel = indentLevel+1; BuildTable(dt);
}
}
private Table GetDetailTable(DataRow dr, int indentLevel)
{
Table DetailTable = new Table();
DetailTable.Width = Unit.Percentage(100);
DetailTable.CssClass = "SortableTable";
TableRow tblRow = new TableRow();
TableCell tblEmptyCell = new TableCell();
tblEmptyCell.Width = Unit.Percentage(5);
tblEmptyCell.Controls.Add(new LiteralControl(string.Empty));
tblEmptyCell.Width = Unit.Percentage(5 * indentLevel);
tblRow.Cells.Add(tblEmptyCell);
//To Display Name
TableCell tblCell = new TableCell();
tblCell.Width = Unit.Percentage(15);
tblCell.CssClass = "alt-row-hover";
LiteralControl lc = new LiteralControl(dr["user_id"].ToString());
tblCell.Controls.Add(lc);
tblCell.HorizontalAlign = HorizontalAlign.Left;
tblRow.Cells.Add(tblCell);
mainTable.Rows.Add(tblRow);
//To Display Detials
TableCell tblCellDetials = new TableCell();
tblCellDetials.CssClass = "alt-row";
tblCellDetials.Width = Unit.Percentage(80);
StringBuilder detailString = new StringBuilder();
detailString.Append("Action: " + Convert.ToString(dr["action_id"]) + "<br>");
detailString.Append("Action Date: " + Convert.ToString(dr["action_date"]) + "<br>");
detailString.Append("Comments: " + Convert.ToString(dr["comments"]) + "<br>");
LiteralControl lcd = new LiteralControl(detailString.ToString());
tblCellDetials.Controls.Add(lcd);
tblCellDetials.HorizontalAlign = HorizontalAlign.Left;
tblRow.Cells.Add(tblCellDetials);
DetailTable.Rows.Add(tblRow);
return DetailTable;
}
}
You don't have anything which decrements indentLevel at the end of BuildTable.
Personally, I would change BuildTable to take the indentLevel as well, and just change this:
if (dt.Rows.Count > 0) indentLevel = indentLevel+1; BuildTable(dt);
to this:
if (dt.Rows.Count > 0)
{
BuildTable(dt, indentLevel + 1);
}
Then just call it initially with:
BuildTable(rootTable, 0);
... and remove the instance variable completely. That way you don't need to decrement indentLevel at all; each nested call will just naturally get the right level.
By the way, C# isn't line-based when it comes to blocks - so currently your code is equivalent to:
// Current code
if (dt.Rows.Count > 0)
{
indentLevel = indentLevel + 1;
}
BuildTable(dt, indentLevel);
That won't actually do any harm in this particular case, as the method does nothing when dt.Rows is empty, but it means your code is somewhat confusing. Personally I prefer to always use braces.
Related
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"
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.
I have a large form I'm transforming into a PDF. The first 1/6th of it looks like this:
http://i.imgur.com/y4pO8Th.png
The number of entered fields however, varies from 1 to 20 per section, and I need to be able to make this document break pages intelligently. My plan was to originally draw the tables piece by piece and just manage the Y-coordinate by grabbing the number of rows in all previous tables. This worked, but falls apart when I get to a page break, and I start needing some semi-complicated logic to make it work, and it's the kind of logic that gets messier and messier with each additional table added.
My second plan was to reproduce the table structure of the HTML document in the PDF, which I manage to do successfully...
private void DrawPDF()
{
Document tDoc = new Document();
MigraDoc.DocumentObjectModel.Style style = tDoc.Styles["Normal"];
style.Font.Name = tPdfFont;
style.Font.Size = 10;
Section tSec = tDoc.AddSection();
MigraDoc.DocumentObjectModel.Tables.Table masterTable = new MigraDoc.DocumentObjectModel.Tables.Table();
masterTable = tSec.AddTable();
masterTable.Borders.Visible = false;
Column leftColumn = masterTable.AddColumn("365pt");
Column spacer = masterTable.AddColumn("10pt");
Column rightColumn = masterTable.AddColumn("365pt");
Row tFS = masterTable.AddRow();
Cell tCell = tFS.Cells[0];
//
// Farm Assets Column
//
{
MigraDoc.DocumentObjectModel.Tables.Table tAssetsTable = new MigraDoc.DocumentObjectModel.Tables.Table();
tAssetsTable.Borders.Visible = false;
Column tColumn = tAssetsTable.AddColumn("365pt");
tCell.Elements.Add(tAssetsTable);
//
// Current Farm Assets
//
for (int i = 0; i < 10; i++) // Drawn 10 times to force it to draw over the 1st page.
{
Section thisSection = tDoc.AddSection();
Row tAssetsRow = tAssetsTable.AddRow();
Cell tAssetsCell = tAssetsRow.Cells[0];
MigraDoc.DocumentObjectModel.Tables.Table table = new MigraDoc.DocumentObjectModel.Tables.Table();
table = thisSection.AddTable();
table.Borders.Width = 0.2;
table.Rows.LeftIndent = 0;
Column columnData = table.AddColumn("295pt");
columnData.Borders.Left.Visible = false;
Column columnValue = table.AddColumn("70pt");
Row rowA = table.AddRow();
rowA.Shading.Color = Color.FromRgbColor((byte)255, Color.Parse("0xa2a2d2"));
rowA.Cells[0].AddParagraph("CURRENT FARM ASSETS");
rowA.Cells[1].AddParagraph("$ Value");
rowA.Cells[1].Format.Alignment = ParagraphAlignment.Right;
Row row1 = table.AddRow();
row1.Borders.Bottom.Visible = false;
row1.Cells[0].AddParagraph("Cash: Savings: ($" + MP.FormFinancialStatement.CurrentStaticAssets.Savings + ") Checking: ($" + MP.FormFinancialStatement.CurrentStaticAssets.Checking + ")");
row1.Cells[1].AddParagraph(MP.FormFinancialStatement.CurrentStaticAssets.CashTotal);
row1.Cells[1].Format.Alignment = ParagraphAlignment.Right;
Row row2 = table.AddRow();
row2.Borders.Bottom.Visible = false;
row2.Cells[0].AddParagraph("Invest: Time Cret $" + MP.FormFinancialStatement.CurrentStaticAssets.TimeCret + " Other: $" + MP.FormFinancialStatement.CurrentStaticAssets.OtherInvestments + "");
row2.Cells[1].AddParagraph(MP.FormFinancialStatement.CurrentStaticAssets.InvestTotal);
row2.Cells[1].Format.Alignment = ParagraphAlignment.Right;
Row row3 = table.AddRow();
row3.Borders.Bottom.Visible = false;
row3.Cells[0].AddParagraph("Replacement Account");
row3.Cells[1].AddParagraph(MP.FormFinancialStatement.CurrentStaticAssets.ReplacementAccount);
row3.Cells[1].Format.Alignment = ParagraphAlignment.Right;
Row row4 = table.AddRow();
row4.Cells[0].AddParagraph("Accouts and Notes Recievable");
row4.Cells[1].AddParagraph(MP.FormFinancialStatement.CurrentStaticAssets.AccountsNotesReceivable);
row4.Cells[1].Format.Alignment = ParagraphAlignment.Right;
MigraDoc.DocumentObjectModel.Tables.Table clone = (MigraDoc.DocumentObjectModel.Tables.Table)table.Clone();
tAssetsCell.Elements.Add(clone);
}
}
MigraDoc.Rendering.DocumentRenderer docRenderer = new DocumentRenderer(tDoc);
docRenderer.PrepareDocument();
docRenderer.RenderObject(gfx, 30, 85, "740pt", masterTable);
}
But alas, this does not actually break pages correctly. I tried sectioning off each individual table, hoping that'd do page break magic, but it does not.
How can I structure this to allow for good page breaks?
You can use the KeepWith property of the table rows to keep blocks together on one page. Only use this for chunks that will surely fit on one page.
See also:
https://stackoverflow.com/a/6831048/1015447
https://stackoverflow.com/a/1327228/1015447
In my Page Load Method, I'm filling an HTML Table with Data.
By Default, the Table is empty.
<table runat="server" id="categoriesTable">
</table>
After I create each Row dynamically, I add 4 cells to it, and I give each cell an ID to be used later.
After creating all Cells, I re-traverse this Table so I can add inside each cell a list <li></li>, The Data inside these lists are fetched from a Database, which depends on the ID given to each Cell previously.
When I refresh the page, nothing goes wrong, but on PostBack's (After clicking on some ASP Button, or changing the Selected Index of a DropDownList), the number of cells stays the same, but the list inside each cell is doubled.
Means, if I had this:
Cell1
-Da
-Do
-Di
-Du
Cell2
-Ya
-Yo
Cell3
-Ka
-Ki
I would have this after the PostBack:
Cell1
-Da
-Do
-Di
-Du
-Da
-Do
-Di
-Du
Cell2
-Ya
-Yo
-Ya
-Yo
Cell3
-Ka
-Ki
-Ka
-Ki
Here is the code, note that cCategory is a class that I created, and its methods return a List<cCategory>.
//Load Categories Into the Table
List<cCategory> mainCategoriesList = cCategory.SubCategories(null);
if(mainCategoriesList.Count!=0)
{
//Categories Available
HtmlTableRow Row = new HtmlTableRow();
categoriesTable.Rows.Add(Row);
HtmlTableCell Cell;
int cellCounter = 0;
while(cellCounter<mainCategoriesList.Count)
{
if (cellCounter % 4 == 0 && cellCounter!=0)
{
//Add a New Row
Row = new HtmlTableRow();
categoriesTable.Rows.Add(Row);
}
Cell = new HtmlTableCell();
Cell.InnerHtml = "" + mainCategoriesList.ElementAt(cellCounter).Category()+ "";
Cell.ID = mainCategoriesList.ElementAt(cellCounter).CategoryID();
Row.Cells.Add(Cell);
cellCounter++;
}
//Now we must add the sub categories
String subList = "";
String newContents;
int counter;
List<cCategory> subCategoriesList;
for (int i = 0; i < categoriesTable.Rows.Count; i++)
{
//For each Row, go through each Cell
for (int j = 0; j < categoriesTable.Rows[i].Cells.Count; j++)
{
//For Each CELL, get the subCategories
subCategoriesList = cCategory.SubCategories(categoriesTable.Rows[i].Cells[j].ID);
counter = 0;
while (counter < subCategoriesList.Count)
{
subList = subList + "<li>" + subCategoriesList.ElementAt(counter).Category() + "</li>";
counter++;
}
newContents = "<div class=\"subCategoriesList\"><ul>" + subList + "</ul></div>";
subList = "";
categoriesTable.Rows[i].Cells[j].InnerHtml = categoriesTable.Rows[i].Cells[j].InnerHtml + newContents;
}
}
}
Why is the Cell data getting doubled?
Do you have an IsPostBack() check in your Page_Load method where you are loading the table? I'm guessing not and that the rows are doubling because they are getting posted back via ViewState and you are adding them again via the above code.
I think you should clean up [or remove the data of] the categoriesTable table first, then you do your logic.
I am having a schedule print from a database and using a loop. I have done this in asp but I am changing to c# asp.net and having troubles.
First I print the schedule headers
time|court|court|court
based on the number of courts then it prints the games.
Next ff the current records date is different the last date it will print the date over the entire table row.
Then it checks to see if the time is of the current record is the same as the last if it is not it prints the time and then the game record if it is it just prints the game record.
My problem is I am declaring the TableRow in the time if statment so when I try to use it in another statment it is out of scope. If I take the tablerow outside of the if statement it doesn't print right.
Here is what I have.
for (int i = 0; i < GameCount; i++)
{
DateTime currentdatetime = (DateTime)Schedules.Tables["Schedule"].Rows[i]["datetime"];
string ndate = currentdatetime.ToString("MM/dd/yyy");
string ntime = currentdatetime.ToString("HH:mm");
string nextdate = currentdatetime.ToString("MM/dd/yyy");
if (i + 1 != GameCount)
{
DateTime nextdatetime = (DateTime)Schedules.Tables["Schedule"].Rows[i + 1]["datetime"];
nextdate = nextdatetime.ToString("MM/dd/yyy");
}
string TeamA = Schedules.Tables["Schedule"].Rows[i]["teamA"].ToString();
string TeamB = Schedules.Tables["Schedule"].Rows[i]["teamB"].ToString();
//check to see if date is current
if (LastDate != ndate)
{
TableRow daterow = new TableRow();
TableCell datecell = new TableCell();
datecell.ColumnSpan = 7;
datecell.Controls.Add(new LiteralControl(ndate));
daterow.Cells.Add(datecell);
ScheduleTable.Rows.Add(daterow);
LastDate = ndate;
}
//print the games
if (currentdatetime != LastDateTime)
{
TableRow gamerow = new TableRow();
TableCell timecell = new TableCell();
timecell.Controls.Add(new LiteralControl(ntime));
gamerow.Cells.Add(timecell);
if (i + 1 != GameCount & ndate != nextdate)
{
ScheduleTable.Rows.Add(gamerow);
}
}//check to see if next game is part of the current row
else
{
TableCell gamecell = new TableCell();
gamecell.Controls.Add(new LiteralControl(TeamA + ".vs." + TeamB));
gamerow.Cells.Add(gamecell);
}
}
I can also post what I currently have in asp if that would help... you can go to www.swgc.ca/volleyball/2011/schedules.asp to see what I am trying to accomplish.
Thanks
Change your last bit to:
TableRow gamerow = new TableRow();
if (currentdatetime != LastDateTime)
{
TableCell timecell = new TableCell();
timecell.Controls.Add(new LiteralControl(ntime));
gamerow.Cells.Add(timecell);
}//check to see if next game is part of the current row
else
{
TableCell gamecell = new TableCell();
gamecell.Controls.Add(new LiteralControl(TeamA + ".vs." + TeamB));
gamerow.Cells.Add(gamecell);
}
if (i + 1 != GameCount & ndate != nextdate)
{
ScheduleTable.Rows.Add(gamerow);
}
And I'd strongly recommend looking at gridviews and repeater/list controls, as this is what they are for.
The easiest solution would be to pull your instantiation outside of the for loop. Try this (untested code):
TableRow gamerow = new TableRow();
TableCell timecell = new TableCell();
TableCell gamecell = new TableCell();
TableRow daterow = new TableRow();
TableCell datecell = new TableCell();
for (int i = 0; i < GameCount; i++)
{
DateTime currentdatetime = (DateTime)Schedules.Tables["Schedule"].Rows[i]["datetime"];
string ndate = currentdatetime.ToString("MM/dd/yyy");
string ntime = currentdatetime.ToString("HH:mm");
string nextdate = currentdatetime.ToString("MM/dd/yyy");
if (i + 1 != GameCount)
{
DateTime nextdatetime = (DateTime)Schedules.Tables["Schedule"].Rows[i + 1]["datetime"];
nextdate = nextdatetime.ToString("MM/dd/yyy");
}
string TeamA = Schedules.Tables["Schedule"].Rows[i]["teamA"].ToString();
string TeamB = Schedules.Tables["Schedule"].Rows[i]["teamB"].ToString();
//check to see if date is current
if (LastDate != ndate)
{
daterow = new TableRow();
datecell = new TableCell();
datecell.ColumnSpan = 7;
datecell.Controls.Add(new LiteralControl(ndate));
daterow.Cells.Add(datecell);
ScheduleTable.Rows.Add(daterow);
LastDate = ndate;
}
//print the games
if (currentdatetime != LastDateTime)
{
gamerow = new TableRow();
timecell = new TableCell();
timecell.Controls.Add(new LiteralControl(ntime));
gamerow.Cells.Add(timecell);
if (i + 1 != GameCount & ndate != nextdate)
{
ScheduleTable.Rows.Add(gamerow);
}
}//check to see if next game is part of the current row
else
{
gamecell = new TableCell();
gamecell.Controls.Add(new LiteralControl(TeamA + ".vs." + TeamB));
gamerow.Cells.Add(gamecell);
}
This is a non-optimized answer for your question. I feel like there is probably a better OO way to achieve your goal, but didn't want to answer a question you didn't ask.