I am trying to make a timetable using a .txt file as a source, but I am having some trouble. I am creating a website, using C# and ASP.NET.
And this is what I get:
I tried so hard to put all the data in the same 5 rows, but it's just seems impossible, they always hop to the different rows. Just to make things clear, this is my expectation:
Just in case, this is the code I wrote, maybe I messed up somewhere:
string[] allLines = File.ReadAllLines(Server.MapPath("App_Data/Classes.txt"))
foreach(string line in allLines){
string[] parts = line.Split(',');
TableRow row = new TableRow();
TableCell number = new TableCell();
TableCell lesson = new TableCell();
TableCell number2 = new TableCell();
TableCell lesson2 = new TableCell();
TableCell number3 = new TableCell();
TableCell lesson3 = new TableCell();
TableCell number4 = new TableCell();
TableCell lesson4 = new TableCell();
TableCell number5 = new TableCell();
TableCell lesson5 = new TableCell();
if (parts[1] == "Monday" & parts[0] == "5a klase")
{
number.Text = parts[2];
lesson.Text = parts[3];
}
if (parts[1] == "Tuesday" & parts[0] == "5a klase")
{
number2.Text = parts[2];
lesson2.Text = parts[3];
}
if (parts[1] == "Wednesday" & parts[0] == "5a klase")
{
number3.Text = parts[2];
lesson3.Text = parts[3];
}
if (parts[1] == "Thursday" & parts[0] == "5a klase")
{
number4.Text = parts[2];
lesson4.Text = parts[3];
}
if (parts[1] == "Friday" & parts[0] == "5a klase")
{
number5.Text = parts[2];
lesson5.Text = parts[3];
}
row.Cells.Add(number);
row.Cells.Add(lesson);
row.Cells.Add(number2);
row.Cells.Add(lesson2);
row.Cells.Add(number3);
row.Cells.Add(lesson3);
row.Cells.Add(number4);
row.Cells.Add(lesson4);
row.Cells.Add(number5);
row.Cells.Add(lesson5);
Table1.Rows.Add(row);
}
Any help is much appreciated!
P.S. Here's how the .txt file looks like (ignore the non-English names, those are school subjects in Lithuanian):
So here's something to start from. I just freehanded it, so I'm sure there's syntax and other errors in there, but try it, change your own code, etc
public class DoWork(){
var scheduleEntries = new List<ScheduleEntry>();
File.ReadAllLines(Server.MapPath("App_Data/Classes.txt")).Select(i=>scheduleEntries.Add(new ScheduleEntry(i)));
var maxRowCount = scheduleEntries.Max(i=>i.Ordinal);
for (int k = 1; k <= maxRowCount; k++){
var tableRow = new TableRow;
// Monday
var mondayCellItem = scheduleEntries.FirstOrDefault(i=>i.Ordinal == k && i.Day == "Monday")
var mondayCell = new TableCell{
Text = $"{mondayCellItem.Class}"
// Tuesday, etc
tableRow.Cells.Add(mondayCell);
tableRow.Cells.Add(tuesdayCell);
//etc
}
}
internal class ScheduleEntry(){
public string Day {get;set;}
public int Ordinal {get;set;}
public string ClassName {get;set;}
public ScheduleEntry(string inRow){
var values = inRow.Split(',');
Day = values[1]; // should do some validation here
Ordinal = int.Parse(values[2]); // and here
ClassName = values[3]; // and here
}
}
}
You can use Linq to split the text file into rows which are already split by the comma. Then it's just a matter of looping all the items. It all works dynamically so you can add as much weekdays and rows per weekday as needed.
//create a list with the rows already split by comma
List<string[]> allRows = File.ReadLines(Server.MapPath("/textfile1.txt")).Select(line => line.Split(',')).ToList();
//group by weekday
var sortedList = allRows.GroupBy(x => x[1]).ToList();
//get the max number of rows needed
var rowCount = sortedList.Max(x => x.Count()) + 1;
//create a new table
Table table = new Table();
//fill the table with rows and columns
for (int i = 0; i < rowCount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < (sortedList.Count * 2); j++)
{
//if it is the first row add the row headers
if (i == 0)
{
row.BackColor = Color.LightGray;
if (j % 2 == 1)
row.Cells.Add(new TableCell() { Text = sortedList[j /2].Key });
else
row.Cells.Add(new TableCell() { Text = "Nr" });
}
else
{
row.Cells.Add(new TableCell());
}
}
table.Rows.Add(row);
}
//loop all the weekdays
for (int i = 0; i < sortedList.Count; i++)
{
int j = 1;
//loop all the items within a weekday
foreach (var item in sortedList[i])
{
//the item[x] is based on the sample txt file, it is the row split by comma index
table.Rows[j].Cells[i * 2].Text = item[2];
table.Rows[j].Cells[(i * 2) + 1].Text = item[3];
j++;
}
}
Related
This question is answered on a basic level on another post: here However for my case I am not able to hard code the validation values into the sheet I am pulling them from a database based on the content of the cell and will need to do a separate validation for 4 columns on every row. Is there a way this can be achieved? Thank you in advance.
// Data Validations //
// Product Validation //
for (int i = 2; i < rowCount; i++)
{
var val = ws.DataValidations.AddListValidation(ws.Cells[i, 5].Address);
val.ShowErrorMessage = true;
val.ErrorTitle = "Entry was invalid.";
val.Error = "Please choose options from the drop down only.";
var ticketEntity = ticketQueryable.Where(o => o.TTSTicketNumber == ws.Cells[i, 3].Value.ToString()).Single<CustCurrentTicketEntity>();
var prodIds = prodExtQueryable.Where(p => p.ZoneId == ticketEntity.ZoneId && p.TicketTypeId == ticketEntity.TicketTypeId);
if (ticketEntity != null)
{
var prodIdsList = new List<int>();
foreach (var prodId in prodIds)
{
prodIdsList.Add(prodId.ProductId);
}
var ProductList = ProductCache.Instance.AllProducts.Where(p => prodIdsList.Contains(p.ProductId)).Select(p => new SelectListItem() { Value = p.ProductId.ToString(), Text = p.Name });
foreach (var Result in ProductList)
{
var product = Result.Text;
val.Formula.Values.Add(product);
}
}
}
So yes as Ernie said What I did was add a second sheet "ProductValidations" and set it to Hidden (unhide it to check that it is working). I then Load my data from the DataTable and then add some basic EPPLUS formatting. I then iterate over the Rows and Insert values into the "ProductValidations" sheet for each cell. Next I convert my column number to the correct Excel Column letter name (A, AC, BCE etc) I then create a string to pass back as an Excel formula targeting the correct range of cells in the "ProductValidations" sheet. Also to anyone having an issue downloading the Excel file from the server this guid method works just fine for me.
public ActionResult DownloadExcel(EntityReportModel erModel, string filename)
{
var dataResponse = iEntityViewService.LoadEntityView(new EntityViewInput
{
SecurityContext = SessionCache.Instance.SecurityContext,
EntityViewName = "Ticket",
Parameters = new Dictionary<string, object> {
{"MinTicketDateTime", "04/26/16"}
}
});
var table = dataResponse.DataSet.Tables[0];
filename = "TICKETS-" + DateTime.Now.ToString("yyyy-MM-dd--hh-mm-ss") + ".xlsx";
using (ExcelPackage pack = new ExcelPackage())
{
ExcelWorksheet ws = pack.Workbook.Worksheets.Add(filename);
//Add second sheet to put Validations into
ExcelWorksheet productVal = pack.Workbook.Worksheets.Add("ProductValidations");
// Hide Validation Sheet
productVal.Hidden = OfficeOpenXml.eWorkSheetHidden.Hidden;
// Load the data from the datatable
ws.Cells["A1"].LoadFromDataTable(table, true);
ws.Cells[ws.Dimension.Address].AutoFitColumns();
int columnCount = table.Columns.Count;
int rowCount = table.Rows.Count;
// Format Worksheet//
ws.Row(1).Style.Font.Bold = true;
List<string> deleteColumns = new List<string>() {
"CurrentTicketId",
};
List<string> dateColumns = new List<string>() {
"TicketDateTime",
"Updated",
"InvoiceDate"
};
ExcelRange r;
// Format Dates
for (int i = 1; i <= columnCount; i++)
{
// if cell header value matches a date column
if (dateColumns.Contains(ws.Cells[1, i].Value.ToString()))
{
r = ws.Cells[2, i, rowCount + 1, i];
r.AutoFitColumns();
r.Style.Numberformat.Format = #"mm/dd/yyyy hh:mm";
}
}
// Delete Columns
for (int i = 1; i <= columnCount; i++)
{
// if cell header value matches a delete column
if ((ws.Cells[1, i].Value != null) && deleteColumns.Contains(ws.Cells[1, i].Value.ToString()))
{
ws.DeleteColumn(i);
}
}
int col = 0;
int Prow = 0;
int valRow = 1;
// Data Validations //
// Iterate over the Rows and insert Validations
for (int i = 2; i-2 < rowCount; i++)
{
Prow = 0;
col++;
valRow++;
// Add Validations At this row in column 7 //
var ProdVal = ws.DataValidations.AddListValidation(ws.Cells[valRow, 7].Address);
ProdVal.ShowErrorMessage = true;
ProdVal.ErrorTitle = "Entry was invalid.";
ProdVal.Error = "Please choose options from the drop down only.";
var ticketEntity = ticketQueryable.Where(o => o.TTSTicketNumber == ws.Cells[i, 3].Value.ToString()).Single<CustCurrentTicketEntity>();
// Product Validation //
var prodIds = prodExtQueryable.Where(p => p.ZoneId == ticketEntity.ZoneId && p.TicketTypeId == ticketEntity.TicketTypeId);
if (ticketEntity != null)
{
var prodIdsList = new List<int>();
foreach (var prodId in prodIds)
{
prodIdsList.Add(prodId.ProductId);
}
var ProductList = ProductCache.Instance.AllProducts.Where(p => prodIdsList.Contains(p.ProductId)).Select(p => new SelectListItem() { Value = p.ProductId.ToString(), Text = p.Name });
//For Each Item in the list move the row forward and add that value to the Validation Sheet
foreach (var Result in ProductList)
{
Prow++;
var product = Result.Text;
productVal.Cells[Prow, col].Value = product;
}
// convert column name from a number to the Excel Letters i.e A, AC, BCE//
int dividend = col;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
// Pass back to sheeet as an Excel Formula to get around the 255 Char limit for Validations//
string productValidationExcelFormula = "ProductValidations!" + columnName + "1:" + columnName + Prow;
ProdVal.Formula.ExcelFormula = productValidationExcelFormula;
}
}
// Save File //
var fileStream = new MemoryStream(pack.GetAsByteArray());
string handle = Guid.NewGuid().ToString();
fileStream.Position = 0;
TempData[handle] = fileStream.ToArray();
// Note we are returning a filename as well as the handle
return new JsonResult()
{
Data = new { FileGuid = handle, FileName = filename }
};
}
}
[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{
if (TempData[fileGuid] != null)
{
byte[] data = TempData[fileGuid] as byte[];
return File(data, "application/vnd.ms-excel", fileName);
}
else
{
//Log err
return new EmptyResult();
}
}
I am using SQLite to store the data for my application.
The application has a UI that loads the data from the SQLite database to display it table by table to the user. Basically the user can click left or right and view the other tables one by one.
The user can also click a button that will show a print preview of the data and let them print it. I have this working, but I am having some issues devising a dynamic way to display ANY table on the print preview screen perfectly. My concerns are if some column titles are too long etc, basically how to calculate the size of each column etc. Should I loop through and find the max character size of any text in the entire column and then set the column width to just wider than that or is there an easier way to do this?
I also write the data-table to a comma separated csv file so it might be a better alternative to use an existing solution to print from a csv file if any of you know such a solution then please suggest it!
Anyway here is the currently existing code:
// ------------------------ code that gets called when the print button is clicked ----------------------------
// holds the row data
List<string[]> myList = new List<string[]>();
if(ReportPage == 1)
{
int rowCount = MyTestTable.RowCount;
for(int i = 0; i <rowCount; i++)
{
MyTestTable.SelectedRowIndex = i;
var row1 = MyTestTable.GetSelectedRow();
var cols1 = row1.ItemArray;
string Col1 = cols1[row1.FindIndexOfColumn("Col1")].ToString();
string Col2 = cols1[row1.FindIndexOfColumn("Col2")].ToString();
string Col3 = cols1[row1.FindIndexOfColumn("Col3")].ToString();
string Col4 = cols1[row1.FindIndexOfColumn("Col4")].ToString();
string Col5 = cols1[row1.FindIndexOfColumn("Col5")].ToString();
string Col6 = cols1[row1.FindIndexOfColumn("Col6")].ToString();
string Col7 = cols1[row1.FindIndexOfColumn("Col7")].ToString();
myList.Add(new string[] { Col1, Col2, Col3, Col4, Col5, Col6, Col7 });
}
string[] cols = new string[7];
cols[0] = "Col1";
cols[1] = "Col2";
cols[2] = "Col3";
cols[3] = "Col4";
cols[4] = "Col5";
cols[5] = "Col6";
cols[6] = "Col7";
PrintUtility.SetUpDocument("TEST", cols, myList);
}
PrintUtility.TestNewReport();
// ---------------------- plugin code that gets called from the application
namespace PrintUtility
{
public class PrintUtility : UserComponentBase
{
public PrintDocument document;
public DataGridView dataGridView;
public PrintUtility()
{
document = new PrintDocument();
dataGridView = new DataGridView();
}
public void SetUpDocument(string title, string[] cols, List<string[]> rows)
{
document = new PrintDocument();
dataGridView = new DataGridView();
document.DocumentName = title;
document.DefaultPageSettings.Landscape = true;
document.PrintPage += PrintPage;
DataGridView dataGrid = new DataGridView();
dataGrid.ColumnCount = cols.Length;
for (int i = 0; i < cols.Length; i++ )
{
dataGrid.Columns[i].Name = cols[i];
}
foreach(string[] row in rows)
{
dataGrid.Rows.Add(row);
}
this.dataGridView = dataGrid;
document.DocumentName = title;
document.PrintPage += PrintPage;
}
public PrintDocument GetDocument()
{
return this.document;
}
private DataTable ConvertListToDataTable(List<string[]> list)
{
// New table.
DataTable table = new DataTable();
// Get max columns.
int columns = 0;
foreach (var array in list)
{
if (array.Length > columns)
{
columns = array.Length;
}
}
// Add columns.
for (int i = 0; i < columns; i++)
{
table.Columns.Add();
}
// Add rows.
foreach (var array in list)
{
table.Rows.Add(array);
}
return table;
}
public void TestNewReport()
{
Report report = new Report(new PdfFormatter());
FontDef fd = new FontDef(report, "Helvetica");
FontProp fp = new FontPropMM(fd, 4);
FontProp fp_Title = new FontPropMM(fd, 6);
FontProp fp_Word = new FontPropMM(fd, 3);
fp_Title.bBold = true;
List<string> columns = new List<string>();
foreach (DataGridViewColumn column in dataGridView.Columns)
{
columns.Add(column.Name.ToString());
}
List<List<string>> rows = new List<List<string>>();
foreach (DataGridViewRow row in dataGridView.Rows)
{
List<string> rowSingle = new List<string>();
foreach (DataGridViewCell cell in row.Cells)
{
try
{
rowSingle.Add(cell.Value.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
rows.Add(rowSingle);
}
// AUDIT TABLE ( This way of doing things is not dynamic )
Page page = new Page(report);
page.SetLandscape();
int x = 10;
int y = 40;
int pastLength = 0;
foreach(string col in columns)
{
x += ((pastLength * 14) + 31);
page.Add(x, y, new RepString(fp_Title, col));
pastLength = col.Length;
}
page.Add(0, 52, new RepString(fp_Title, "_________________________________________________________________"));
/* Dynamic way starting
int rowX = 10;
int rowY = 105;
foreach (List<string> row in rows)
{
int pastLength2 = 0;
foreach (string rowItem in row)
{
page.Add(rowX, rowY, new RepString(fp_Word, rowItem));
rowX += ((pastLength * 14) + 31);
pastLength2 = rowItem.Length;
}
rowY += 30;
}
*/
fp_Title.rSizeMM = 8;
int amountRowsPerPageSoFar = 0;
int rowY = 80;
foreach (List<string> row in rows)
{
try
{
string iDItem = row[0];
page.Add(40, rowY, new RepString(fp_Word, iDItem));
string typeItem = row[1];
page.Add(120, rowY, new RepString(fp_Word, typeItem));
string descriptionItem = row[2];
page.Add(190, rowY, new RepString(fp_Word, descriptionItem));
string timestampItem = row[3];
page.Add(375, rowY, new RepString(fp_Word, timestampItem));
string userItem = row[4];
page.Add(555, rowY, new RepString(fp_Word, userItem));
string stationItem = row[5];
page.Add(655, rowY, new RepString(fp_Word, stationItem));
string activeItem = row[6];
page.Add(775, rowY, new RepString(fp_Word, activeItem));
amountRowsPerPageSoFar++;
rowY += 30;
if (amountRowsPerPageSoFar >= 17)
{
page = new Page(report);
page.SetLandscape();
amountRowsPerPageSoFar = 0;
rowY = 40;
}
}
catch (Exception ex)
{
}
}
RT.ViewPDF(report, "TestReport.pdf");
}
}
}
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 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.
I have an asp.net table control like this:
TableHeader
A Text | Textbox
What I want to do is, in the page_load event, duplicate second row with all the controls within it, change the text in the first cell and add as a new row. So here is my code:
for (int i = 0; i < loop1counter; i++)
{
TableRow row = new TableRow();
row = myTable.Rows[1]; //Duplicate original row
char c = (char)(66 + i);
if (c != 'M')
{
row.Cells[0].Text = c.ToString();
myTable.Rows.Add(row);
}
}
But when I execute this code it justs overwrites on the original row and row count of the table doesn't change. Thanks for help....
As thekip mentioned, you are re-writing the reference.
Create a new row. Add it to the grid and then copy the cell values in whatever manner you want.
Something like:
TableRow tRow = new TableRow();
myTable.Rows.Add(tRow);
foreach (TableCell cell in myTable.Rows[1].Cells)
{
TableCell tCell = new TableCell();
tCell.Text = cell.Text;
tRow.Cells.Add(tCell);
}
It gets overwritten because you overwrite the reference. You don't do a copy, essentially the row = new TableRow() is doing nothing.
You should use
myTable.ImportRow(myTable.Rows[1]).
Adjusted based on response try:
row = myTable.Rows[1].MemberwiseClone();
so try this
private TableRow CopyTableRow(TableRow row)
{
TableRow newRow = new TableRow();
foreach (TableCell cell in row.Cells)
{
TableCell tempCell = new TableCell();
foreach (Control ctrl in cell.Controls)
{
tempCell.Controls.Add(ctrl);
}
tempCell.Text = cell.Text;
newRow.Cells.Add(tempCell);
}
return newRow;
}
your code:
for (int i = 0; i < loop1counter; i++)
{
TableRow row = CopyTableRow(myTable.Rows[1]); //Duplicate original row
char c = (char)(66 + i);
if (c != 'M')
{
row.Cells[0].Text = c.ToString();
myTable.Rows.Add(row);
}
}