Use dynamic table to display list of string - c#

I tried to display the list of time slots by using dynamic table in C#. However, it does not work properly. Here is my result:
And here is my code
List<AvailableTime> AllTimeSlots = RequestDirector.ListAllAvailableTimes(BookingDate);
foreach (AvailableTime resultTimeslot in AllTimeSlots)
{
TableRow TimeSLotRow = new TableRow();
TableCell TimeSlotCell = new TableCell();
TimeSlotCell.Text = Convert.ToString(resultTimeslot.TimeSlot);
TimeSLotRow.Cells.Add(TimeSlotCell);
Table1.Rows.Add(TimeSLotRow);
}
I want to display 5 time slots each row. Can anybody tell me how I can do that?

Probably something like this :
int i = 0;
TableRow TimeSLotRow = new TableRow();
foreach (AvailableTime resultTimeslot in AllTimeSlots)
{
TableCell TimeSlotCell = new TableCell();
TimeSlotCell.Text = Convert.ToString(resultTimeslot.TimeSlot);
TimeSLotRow.Cells.Add(TimeSlotCell);
i++;
if(i == 5)
{
Table1.Rows.Add(TimeSLotRow);
TimeSLotRow = new TableRow();
i = 0;
}
}

Related

Selecting a dynamically created table row in ASP.NET with C#

I am writing a web application in Visual Studio 2015 pro using C# and ASP.NET. Right now, I have it set up where the user will click a button and the C# code will go get a bunch of data then display it back to the user in tables. I have spent a day of work trying to figure out how to add some form of a clickable event to the table rows but have had no success. Ultimately, what I want to do is call a method in my C# code when the table row is clicked and send it the row index.
Here is the C# code I am using for generating the tables:
protected void searchButton_Click(object sender, EventArgs e)
{
try
{
// Remove the error display
resultListLabel.Style.Add("Display", "None");
// Get document groups
groups = TableCommands.getGroups(dbConn, "retriever", searchTextOne.Text, searchTextTwo.Text);
foreach (var dataPair in groups)
{
// Get data pair group names into list
List<string> name = dataPair.Key.Split('|').ToList();
// ====== Make table
Table resultTable = new Table();
resultTable.Attributes["class"] = "displayTable";
resultList.Controls.Add(resultTable);
// ====== Add table info row
TableRow groupInfo = new TableRow();
groupInfo.Attributes["class"] = "groupInfoLabel";
// add row to table
resultTable.Rows.Add(groupInfo);
// create cell with information
TableCell infoCell = new TableCell();
infoCell.Text = "MRN: "+name[0]+", Name: " + name[1];
infoCell.ColumnSpan = 3;
// add cell to row
groupInfo.Cells.Add(infoCell);
// ====== Make column label row
TableRow labelRow = new TableRow();
labelRow.Attributes["class"] = "columnLabel";
// add row to table
resultTable.Rows.Add(labelRow);
// make an array of column lables
string[] cellNames = new string[] { "Visit Date", "Document Type", "Doctor ID" };
// add column lables to row
foreach (string s in cellNames)
{
TableCell labelCell = new TableCell();
labelCell.Text = s;
labelRow.Cells.Add(labelCell);
}
// Add display names to table
foreach(var nameList in dataPair.Value)
{
TableRow nameRow = new TableRow();
nameRow.Attributes["class"] = "columnInfo";
for (int i = 0; i < 3; i++)
{
TableCell nameCell = new TableCell();
nameCell.Text = nameList[i];
nameRow.Cells.Add(nameCell);
}
resultTable.Rows.Add(nameRow);
}
}
}
catch(Exception ex)
{
// Display the error and write to log
resultListLabel.Style.Add("Display", "Inline-Block");
writeLog("Failed to generate tables", ex.ToString());
}
}
Here's what I had to do:
Add a global boolean to called tableCall to the C# code
Move the code in searchButton_Click into an if(tableCall) statement in the Page_Load method.
protected void Page_Load(object sender ,EventArgs e){
...
if(tableCall){
//Do stuff from searchButton_Click
}
...
}
Add tableCall = true; and Page_Load(sender, e) to searchButton_Click
Modify the for loop to add buttons in the cell like so:
// Add display names to table
foreach (var nameList in dataPair.Value)
{
TableRow nameRow = new TableRow();
nameRow.Attributes["class"] = "columnInfo";
// Add display names to table
foreach (var nameList in dataPair.Value)
{
TableRow nameRow = new TableRow();
nameRow.Attributes["class"] = "columnInfo";
for (int i = 0; i < 3; i++)
{
TableCell nameCell = new TableCell();
nameRow.Cells.Add(nameCell);
Button b = new Button();
b.Attributes["class"] = "docButton";
b.Attributes.Add("DWdocid", nameList[3]);
b.Text = nameList[i];
b.Click += new EventHandler((s, ea) => test(s, ea, b.Attributes["DWdocid"]));
nameCell.Controls.Add(b);
}
resultTable.Rows.Add(nameRow);
}
This adds a button to each of the three cells in the row, but adds the same document id to each of the buttons in that row, so anywhere the user clicks on that row (except for the 1px borders) will call a method in the C# code while passing it the document ID. I'm sure that with better css skills somebody could make the button span all three cells.

How do I make this table shorter?

I think I'm doing something terribly wrong here. I have a object inside import called oCultivationPlan. It contains data obviously. And I want to create a table which shows the data inside it. However I only want a selected few from that object and not all the data in it. Is there a way to make this shorter? I thought about using foreach or for, but that would loop through all the data inside the object :/ while I only want a selected few.
TableRow tblRow = new TableRow();
TableCell tblc = new TableCell();
tblc.Controls.Add(new LiteralControl("ID"));
TableCell tblc2 = new TableCell();
tblc2.Controls.Add(new LiteralControl(import.oCultivationPlan.iID.ToString()));
tblRow.Controls.Add(tblc);
tblRow.Controls.Add(tblc2);
tblImportPreview.Controls.Add(tblRow);
TableCell tblc3 = new TableCell();
TableCell tblc4 = new TableCell();
tblc3.Controls.Add(new LiteralControl("Description"));
tblc4.Controls.Add(new LiteralControl(import.oCultivationPlan.sDescription.ToString()));
TableRow tblRow2 = new TableRow();
tblRow2.Controls.Add(tblc3);
tblRow2.Controls.Add(tblc4);
tblImportPreview.Controls.Add(tblRow2);
TableCell tblc5 = new TableCell();
TableCell tblc6 = new TableCell();
tblc5.Controls.Add(new LiteralControl("DateCreated"));
tblc6.Controls.Add(new LiteralControl(import.oCultivationPlan.dDateCreated.ToString()));
TableRow tblRow3 = new TableRow();
tblRow3.Controls.Add(tblc5);
tblRow3.Controls.Add(tblc6);
tblImportPreview.Controls.Add(tblRow3);
not a foreach :) but you can use a for loop to get trough it. you should be able to use the code below as a solution for your question :)
its smaller cuz of the loop but it does the exact same thing as what you did. I use the string array to keep all the info you want to get inside the table so that it will be having something to go out after.
For each row you have you got 2 new cells in it and thats why we have the row*2 so the cells can get filled up :)
Hope it works for you and that you can use the solution :)
int _row = 1;
int _cell = 0;
string[] arr = new string[6] { "ID", import.oCultivationPlan.iID.ToString(), "Description", import.oCultivationPlan.sDescription.ToString(), "DateCreated", import.oCultivationPlan.dDateCreated.ToString() };
for (; _row <= 3; _row++)
{
TableRow tblRow = new TableRow();
for (; _cell < _row * 2; _cell++)
{
TableCell tblc = new TableCell();
tblc.Controls.Add(new LiteralControl(arr[_cell]));
tblRow.Controls.Add(tblc);
}
tblImportPreview.Controls.Add(tblRow);
}
I would create a strong typed Class
public Class ImportDto
{
public string RowIdentifier {get; set;}
public string RowValue {get; set;
}
Then as David said, write a filter function to filter data from Import class and map it to ImportValues
public List<ImportDto> FilterImportedData(Import import)
{
var importDto = new List<ImportDto>
{
new ImportDto { RowIdentifier ="ID", RowValue = import.oCultivationPlan.iID.ToString()},
new ImportDto { RowIdentifier ="Description", RowValue = import.oCultivationPlan.sDescription.ToString()}
};
}
Then in the aspx.cs class, just loop through List<ImportDto>and create LiteralControls
foreach(var dto in importDtos)
{
var row = new TableRow();
var identifierCell = new TableCell();
var valueCell = new TableCell();
identifierCell.Controls.Add(new LiteralControl(dto.RowIdentifier));
valueCell.Controls.Add(new LiteralControl(dto.RowValue ));
row.Add(identifierCell);
row.Add(valueCell);
tblImportPreview.Controls.Add(row);
}
That way all you need to do in future to add new filtered data, is to modify your mapping function and add a new ImportDto, and the it will be displayed in the frontend automatically.

LINQ to replace foreach in Table creation

I need to create a Table (LINQ to replace foreach in TableRow creation) by adding rows corresponding to objects in a generic list. We can do it as listed below using a foreach loop. How can we achieve this functionality using LINQ without foreach?
Note: One table cell need to be added corresponding to each property in the object.
System.Web.UI.WebControls.Table tableControl = new Table();
foreach (FinancialTransaction transaction in transactionsList)
{
TableRow row = new TableRow();
TableCell cellLineNumber = new TableCell();
cellLineNumber.Text = Convert.ToString(transaction.Line);
row.Cells.Add(cellLineNumber);
TableCell cellEmpID = new TableCell();
cellEmpID.Text = Convert.ToString(transaction.EmpID);
row.Cells.Add(cellEmpID);
TableCell cellSSN = new TableCell();
cellSSN.Text = transaction.SSN;
row.Cells.Add(cellSSN);
tableControl.Rows.Add(row);
}
You can use ForEach LINQ if transactionsList is List, but you could improve readability a little bit:
transactionsList.ForEach(transaction => {
TableRow row = new TableRow();
valueList = new object[] {
transaction.Line,
transaction.EmpID,
transaction.SSN
};
row.Cells.AddRange(valueList.Select(value => CreateCell(value))
.ToArray());
});
private TableCell CreateCell(object cellText)
{
TableCell cell = new TableCell();
cell.Text = Convert.ToString(cellText);
return cell;
}
You can also use Aggregate:
var tableControl = transactionsList.Aggregate(new Table(), (acc, transaction) =>
{
TableRow row = new TableRow();
TableCell cellLineNumber = new TableCell();
cellLineNumber.Text = Convert.ToString(transaction.Line);
row.Cells.Add(cellLineNumber);
TableCell cellEmpID = new TableCell();
cellEmpID.Text = Convert.ToString(transaction.EmpID);
row.Cells.Add(cellEmpID);
TableCell cellSSN = new TableCell();
cellSSN.Text = transaction.SSN;
row.Cells.Add(cellSSN);
acc.Rows.Add(row);
return acc;
});
How about the foreach of Linq itself?
or check this link
It is also possible to create your own Extension Methods

Nested lists and foreach loops

I want to add a single row to the table from the two lists. i am getting an error in the second foreach loop. Cannot convert Liability.LiabilityCheckpointInstance to Liability.LiabilityAssignment.
foreach (LiabilityCheckpointInstance ci in value)
{
//foreach (LiabilityAssignment la in value)
//{
var tr = new TableRow();
var tc = new TableCell { Text = ci.CheckGroup };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.IxCheck.ToString() };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.CheckPointInfo.ToString() };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.RejectedBy };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.Role };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.Mistakes.ToString() };
tr.Cells.Add(tc);
//ChkpLiabilityDataTable.Rows.Add(tr);
foreach (LiabilityAssignment la in value )
{
//var tr = new TableRow();
tc = new TableCell { Text = la.LiabileOrganizationName };
tc = new TableCell { Text = la.LiabileOrganizationName };
tr.Cells.Add(tc);
tc = new TableCell { Text = la.LiablePersonName };
tr.Cells.Add(tc);
tc = new TableCell { Text = la.Comment };
tr.Cells.Add(tc);
ChkpLiabilityDataTable.Rows.Add(tr);
}
}
Your foreach loops are:
foreach (LiabilityCheckpointInstance ci in value)
foreach (LiabilityAssignment la in value )
It is looping over the same thing (value) but saying the items in it are different. [1]
I would assume from the context that the second should be looping over ci.something rather than just value.
So you would have:
foreach (LiabilityAssignment la in ci.Something )
Of course you will need to change the Something to whatever your list is.
[1] I should note that the syntax itself is not incorrect. If the items in value is of both types then (eg one is a subtype of the other) it would work fine. This doesn't look like it is the case here though.
This should do the trick for you.
foreach (LiabilityCheckpointInstance ci in value)
{
var tr = new TableRow();
var tc = new TableCell { Text = ci.CheckGroup };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.IxCheck.ToString() };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.CheckPointInfo.ToString() };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.RejectedBy };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.Role };
tr.Cells.Add(tc);
tc = new TableCell { Text = ci.Mistakes.ToString() };
tr.Cells.Add(tc);
// YOU NEED TO BUILD THESE UP FRONT SO YOU CAN LOOP THROUGH THE
// CHILDREN SAFELY BELOW
tr.Cells.Add(new TableCell());
tr.Cells.Add(new TableCell());
tr.Cells.Add(new TableCell());
// I DON'T KNOW IF YOUR PROPERTY IS NAMED LiabilityAssignments OR NOT
// SO REPLACE THAT WITH WHAT EVER IS NECESSARY - BUT IT SHOULD BE THE
// LIST OF LiabilityAssignment ON THE LiabilityCheckpointInstance OBJECT
foreach (LiabilityAssignment la in ci.LiabilityAssignments)
{
tr.Cells[6].Text = la.LiabileOrganizationName;
tr.Cells[7].Text = la.LiablePersonName;
tr.Cells[8].Text = la.Comment;
ChkpLiabilityDataTable.Rows.Add(tr);
}
}
you are using 'value' as the source list for both foreach statements. value apparently contains LiabilityCheckpointInstance objects, so it fails when you try to use it as if it contained LiabilityAssignment objects.
Did you means to sa: foreach (LiabilityAssignment la in ci.)?
Second loop should be
foreach (LiabilityAssignment la in ci)

c# asp.net table row always going in the same row

I have this code
protected void Page_Load(object sender, EventArgs e)
{
TblPrikaz.BorderWidth = 1;
XmlDocument baza = new XmlDocument();
XmlTextReader reader = new XmlTextReader(Server.MapPath("baza.xml"));
baza.Load(reader);
TableRow line = new TableRow();
TableCell id = new TableCell();
TableCell ime = new TableCell();
TableCell prezime = new TableCell();
TableCell godiste = new TableCell();
id.Text = "ID";
ime.Text = "Ime";
prezime.Text = "Prezime";
godiste.Text = "Godiste";
line.BackColor = Color.Green;
line.Cells.Add(id);
line.Cells.Add(ime);
line.Cells.Add(prezime);
line.Cells.Add(godiste);
TblPrikaz.Rows.Add(line);
XmlNodeList popis = baza.GetElementsByTagName("element");
for (int i = 0; i < popis.Count; i++)
{
if (string.Compare(popis[i].Attributes["ID"].Value.ToString(), "0") == 0) continue;
id.Text = popis[i].Attributes["ID"].Value.ToString();
ime.Text = popis[i].ChildNodes[0].InnerText;
prezime.Text = popis[i].ChildNodes[1].InnerText;
godiste.Text = popis[i].ChildNodes[2].InnerText;
line.Cells.Add(id);
line.Cells.Add(ime);
line.Cells.Add(prezime);
line.Cells.Add(godiste);
TblPrikaz.Rows[i].Cells.Add(id);
TblPrikaz.Rows[i].Cells.Add(ime);
TblPrikaz.Rows[i].Cells.Add(prezime);
TblPrikaz.Rows[i].Cells.Add(godiste);
}
}
for some reason, the table only shows the loast row read fromthe document and I have no idea why it is doing that.
Anyone have an idea?
You are not creating a new row on each iteration. Instead, you are updating the existing row.
XmlNodeList popis = baza.GetElementsByTagName( "element" );
for ( int i = 0; i < popis.Count; i++ )
{
var element = popis[i];
if ( element == null || element.Attributes == null )
continue;
if ( element.Attributes["ID"].Value.ToString() == "0" )
continue;
var idCell = new TableCell { Text = element.Attributes["ID"].Value.ToString() };
var imeCell = new TableCell { Text = element.ChildNodes[0].InnerText };
var prezimeCell = new TableCell { Text = element.ChildNodes[1].InnerText };
var godisteCell = new TableCell { Text = element.ChildNodes[2].InnerText };
var row = new TableRow();
row.Cells.Add( idCell );
row.Cells.Add( imeCell );
row.Cells.Add( prezimeCell );
row.Cells.Add( godisteCell );
TblPrikaz.Rows.Add( row );
}
Your table always use the same row and cell objects, you need to create new ones in the loop:
id = new TableCell();
etc....

Categories

Resources