I started a new answer.
So, additions are a combo box example, and a file uploader for each row.
Hence this markup now:
<asp:ListView ID="ListView1" runat="server"
DataKeyNames="ID"
OnItemDataBound="ListView1_ItemDataBound" >
<ItemTemplate>
<tr>
<td>
<asp:TextBox ID="txtFirst" runat="server" Text='<%# Eval("Firstname") %>' Width="90px"/> </td>
<td>
<asp:TextBox ID="txtLast" runat="server" Text='<%# Eval("LastName") %>' Width="90px" /></td>
<td>
<asp:DropDownList ID="cboCity" runat="server"
DataTextField="City">
</asp:DropDownList>
</td>
<td>
<asp:TextBox ID="txtHotel" runat="server" Text='<%# Eval("HotelName") %>'
width="220px" /></td>
<td>
<asp:TextBox ID="txtDescription" runat="server" TextMode="MultiLine"
width="270px" Rows="2"
Text='<%# Eval("Description") %>' /></td>
<td style="text-align:center">
<asp:CheckBox ID="Active" runat="server" /></td>
<td>
<asp:TextBox ID="txtBookingDate" runat="server"
Text='<%# Eval("BookingDate","{0:d}") %>'
TextMode="Date"
/></td>
<td>
<button id="cmdDelete" runat="server" class="btn myshadow" style="margin-left:15px"
onserverclick="cmdDelete_ServerClick"
>
<span aria-hidden="true" class="glyphicon glyphicon-trash"></span>
</button>
</td>
<td>
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:TextBox ID="txtFileName" runat="server"
Text='<%# Eval("UpLoadFile") %>'
onclick="mytoggle(this)"
>
</asp:TextBox>
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0"
style="width:100%" class="table table-hover table-bordered">
<tr runat="server">
<th runat="server">First Name</th>
<th runat="server">Last Name</th>
<th runat="server">City</th>
<th runat="server">Hotel Name</th>
<th runat="server">Description</th>
<th runat="server">Active</th>
<th runat="server">Booking Date</th>
<th runat="server">Delete</th>
<th runat="server">File</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
<button id="cmdAdd" runat="server" class="btn myshadow"
onserverclick="cmdAdd_Click1">
<span aria-hidden="true" class="glyphicon glyphicon glyphicon-share"> Add</span>
</button>
<button id="cmdSave" runat="server" class="btn myshadow" style="float:right"
onserverclick="cmdSave_Click1">
<span aria-hidden="true" class="glyphicon glyphicon-floppy-saved"> Save</span>
</button>
And our code behind is this:
private DataTable rstPeople = new DataTable();
private DataTable rstCity = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadGrid();
Session["MyTable"] = rstPeople;
}
else
rstPeople = (DataTable)Session["MyTable"];
}
public void LoadGrid()
{
string strSQL = "SELECT City FROM City ORDER BY City";
rstCity = General.MyRst(strSQL); // load city choices before binding
strSQL = @"SELECT * FROM tblHotelsA ORDER BY HotelName";
rstPeople = General.MyRst(strSQL);
rstPeople.PrimaryKey = new DataColumn[] { rstPeople.Columns["ID"] };
ListView1.DataSource = rstPeople;
ListView1.DataBind();
}
public void LoadGridMemory()
{
string strSQL = "SELECT City FROM City ORDER BY City";
rstCity = General.MyRst(strSQL); // load city choices before binding
ListView1.DataSource = rstPeople;
ListView1.DataBind();
}
protected void cmdSave_Click1(object sender, EventArgs e)
{
// pull grid rows back to table.
GridToTable();
// now send table back to database with updates
string strSQL = "SELECT * FROM tblHotelsA WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstPeople);
}
}
void GridToTable()
{
foreach (ListViewItem rRow in ListView1.Items)
{
int PK = (int)ListView1.DataKeys[rRow.DataItemIndex]["ID"];
DataRow OneDataRow = rstPeople.Rows.Find(PK);
OneDataRow["FirstName"] = ((TextBox)rRow.FindControl("txtFirst")).Text;
OneDataRow["LastName"] = ((TextBox)rRow.FindControl("txtLast")).Text;
OneDataRow["City"] = ((DropDownList)rRow.FindControl("cboCity")).Text;
OneDataRow["HotelName"] = ((TextBox)rRow.FindControl("txtHotel")).Text;
OneDataRow["Description"] = ((TextBox)rRow.FindControl("txtDescription")).Text;
OneDataRow["Active"] = ((CheckBox)rRow.FindControl("Active")).Checked;
TextBox tDate = (TextBox)rRow.FindControl("txtBookingDate");
if (tDate.Text == "")
{
OneDataRow["BookingDate"] = DBNull.Value;
}
else
{
DateTime BookingDate = DateTime.ParseExact(tDate.Text, "d", null);
OneDataRow["BookingDate"] = BookingDate;
}
FileUpload MyFile = (FileUpload)rRow.FindControl("FileUpLoad1");
if (MyFile.HasFile)
{
// save the file to the uploads folder
string sServerFile = Server.MapPath($@"~/UpLoadFiles/{MyFile.FileName}");
MyFile.SaveAs(sServerFile);
OneDataRow["UpLoadFile"] = MyFile.FileName;
}
}
}
protected void cmdAdd_Click1(object sender, EventArgs e)
{
// add a new row to the grid
GridToTable(); // save any pending edits
DataRow OneRow = rstPeople.Rows.Add();
rstCity = General.MyRst("SELECT City FROM City ORDER BY City");
ListView1.DataSource = rstPeople;
ListView1.DataBind();
ListViewItem NewRow = (ListViewItem)ListView1.Items[ListView1.Items.Count - 1];
TextBox txtFirst = (TextBox)NewRow.FindControl("txtFirst");
txtFirst.Focus();
}
protected void cmdDelete_ServerClick(object sender, EventArgs e)
{
HtmlButton cmdDel = (HtmlButton)sender;
ListViewItem lvRowToDel = (ListViewItem)cmdDel.NamingContainer;
int PK = (int)ListView1.DataKeys[lvRowToDel.DataItemIndex]["ID"];
rstPeople.Rows.Find(PK).Delete();
ListView1.DataSource = rstPeople;
ListView1.DataBind();
}
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
DataRowView RowData = (DataRowView)e.Item.DataItem;
DropDownList cboCity = (DropDownList)e.Item.FindControl("cboCity");
cboCity.DataSource = rstCity;
cboCity.DataBind();
cboCity.Items.Insert(0, "Select City");
if (RowData["City"] != null)
{
cboCity.Text = RowData["City"].ToString();
}
FileUpload MyFileUpLoader = (FileUpload)e.Item.FindControl("FileUpLoad1");
TextBox UpLoadFile = (TextBox)e.Item.FindControl("txtFileName");
if (RowData["UpLoadFile"] == DBNull.Value)
{
MyFileUpLoader.Style.Add("display", "inline");
UpLoadFile.Style.Add("display", "none");
}
else
{
MyFileUpLoader.Style.Add("display", "none");
UpLoadFile.Style.Add("display", "inline");
}
}
}
And now our result is this:
So, certainly some more love to this page should be added. I would for example add a "wait" spinner when save is pressed, since uploading of files could cause quite a noticeable delay, but such tweaks and polishing up can be added to the above proof of concept. I assume that save redirects to some other page after saving. I also currently do save the pending up-loads when you add a new row. This saved a lot of code issues. I suppose we could defer the uploading only on save button. But above is a great proof of concept here.