关于 C# 中 Asp.net 中的 Gridview 和数据的问题
Question about Gridview and data in Asp.net with C#
我正在制作一个模块以将数组保存在 SQL 数据库中。例如,我想保存 (889,4,01/12/2021)
、(889,4,02/12/2021)
和 (889,4,03/12/2021)
.
我正在使用 gridview 获取第一个值 (889
)。然后我用文本框获取日期,然后我 运行 查询 return 行中的日期并存储在 gridview 中。
我正在尝试使用 GridView2.Rows[0].Cells[1].Text
选择第二个 gridview 值 (date
),但超出了有效值的范围。
因为这是一个数组,所以我将所有 SQL 句子保存在一个文本框中,稍后再执行,这就是我的代码
string[,] arreglo = new string[GridView1.Rows.Count, 7];
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox chkbox1 = (CheckBox)row.FindControl("chkActive");
if (chkbox1.Checked)
{
arreglo[row.RowIndex, 0] = GridView1.Rows[row.RowIndex].Cells[1].Text;
string[,] array = new string[GridView2.Rows.Count, 2];
foreach (GridViewRow col in GridView2.Rows)
array[col.RowIndex, 0] = GridView2.Rows[col.RowIndex].Cells[1].Text;
txtInsert.Text = txtInsert.Text + "insert into T_USUARIO_dETALLE(id_usuario,campana,fecha,fecha_carga,id_superv,estado_dotacion) values ('" + arreglo[row.RowIndex, 0].ToString() + "', '" + lblcampana.Text + "','"+ GridView2.Rows[0].Cells[1].Text + "','" + LBLSUPERV.Text + "','" + ddlEstado.SelectedValue + "')";
}
}
感谢帮助!!!
好的,这是 db land 中最经典的设置之一!
我们有一些父记录,对于每条记录,我们需要显示(和编辑)子行。
现在有更多 UI 口味的冰淇淋可供选择。
这表明我们需要“嵌套”主记录(比如在网格中)以显示子记录(我们的第二个网格)。
好吧,事实证明网格真的不能很好地嵌套。
因此,对于父记录,让我们使用 ListView - 它们工作得更好。
好的,所以我们可以启动向导 - 构建 LV,然后在这里使用核武器并删除 + 炸毁所有模板。在我们添加这个的同时,删除额外的嵌套 table。我算了 < 2 分钟的时间。
所以,我们现在有了这个简单的 LV。
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >
<ItemTemplate>
<tr>
<td><asp:Button ID="cmdView" runat="server" Text="+" /></td>
<td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
<td><asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' /></td>
<td><asp:Label ID="ProvinceLabel" runat="server" Text='<%# Eval("Province") %>' /></td>
<td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" class = "table table-hover" >
<tr runat="server" style="">
<th runat="server">View</th>
<th runat="server">HotelName</th>
<th runat="server">City</th>
<th runat="server">Province</th>
<th runat="server">Description</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
我们要填写的代码是这样的:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadMainGrid();
}
void LoadMainGrid()
{
string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
ListView1.DataSource = MyRst(strSQL);
ListView1.DataBind();
}
我们现在有这个:
好的,现在我们需要子网格。
然后我们将这个作为子网格移动到上面的LV中。
所以,现在我们有了这个标记:
<td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
</tr>
<tr>
<td colspan="5">
<div id="MyGrid" runat="server" style="display:none;margin-left:1%">
<div>
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover table-responsive borderhide" >
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Start date">
<ItemTemplate>
<asp:TextBox ID="dtStart" runat="server" Text='<%# Eval("dtStart", "{0:yyyy-MM-ddTHH:mm}") %>' TextMode="DateTimeLocal" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="End date">
<ItemTemplate>
<asp:TextBox ID="dtEnd" runat="server" Text='<%# Eval("dtEnd","{0:yyyy-MM-ddTHH:mm}") %>' TextMode="DateTimeLocal" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<div style="float:right;margin-right:-10px">
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" OnClick="cmdSave_Click" />
<asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" OnClick="cmdAdd_Click" />
</div>
</div>
</td>
所以我们在 lv 列的标记之后右上角。
现在,我们要做的就是连接“+”按钮展开:
这是 LV 中的第一行按钮
<td><asp:Button ID="cmdView" runat="server" Text="+" OnClick="cmdView_Click"/></td>
代码是这样的:
protected void cmdView_Click(object sender, EventArgs e)
{
Button cmd = (Button)sender;
ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
GridView gChild = (GridView)gVR.FindControl("GridView2"); // pluck out the grid for this row
HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");
//if (gChild.Style["display"] == "normal")
if (MyDiv.Style["display"] == "normal")
{
// if grid is already display, then hide it, and exit
MyDiv.Style["display"] = "none";
return;
}
MyDiv.Style["display"] = "normal";
int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];
// only re-load if never loaded
if (gChild.Rows.Count == 0)
{
gChild.DataSource = MyRst("SELECT * from People where hotel_id = " + HotelPK);
gChild.DataBind();
}
}
所以,现在我们有了这个:
好的,现在我们要做的就是创建一个“保存”按钮,用于保存我们对此 GV 所做的任何更改。
这很简单,所以我们放入一个保存按钮,如下所示:
因此,在我们的网格正下方,我们放入:
</asp:GridView>
</div>
<div style="float:right;margin-right:-10px">
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />
<asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" />
</div>
</div>
我们现在有这个:
好的,那么对于按钮,我们添加一个点击事件:
(只需输入 onclick= 并且 intelsense 会提供创建点击事件的功能,看起来什么都没发生,但是转到后面的代码,您会看到偶数存根。
我们使用这个代码:
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
// send grid to table
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT * from People WHERE hotel_id = " + HotelID;
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
DataTable rstGrid = new DataTable();
rstGrid.Load(cmdSQL.ExecuteReader());
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"]= DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
da.Update(rstGrid);
}
}
}
好的,我们不妨连接“新行按钮”。
所以对于那个代码我们有这个:
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
string strSQL = "INSERT INTO People (Hotel_ID) VALUES(" + HotelID + ")";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
cmdSQL.ExecuteNonQuery();
}
DataTable rstGrid = MyRst("SELECT * from People where Hotel_ID = " + HotelID);
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
}
}
我还有一个辅助例程 - 它是一个全局函数,对于给定的 sql 字符串,它只是 returns 数据 table。我在上面确实用过几次。
这个例程:
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
Edit/Upate(使 UI 更好):
一个问题?
如果用户点击添加新行,他们无疑会开始打字,然后很可能再次点击添加新行(但在上面,他们必须先点击保存数据)。
所以,我建议在添加新行之前保存数据。
这迫使我们无论如何都要打破那个更长的例程。
所以我们添加一个“Grid to Table”,然后添加一个“save table”到数据库。将其分成两步不仅修复了上面的“错误”或“问题”,而且实际上减少了代码。
所以,我建议更新这 3 个(以及 4 个)例程,它们都更短,应该使用。
因此,添加行、保存编辑和 MyRst 都已更新。
我建议使用此代码,因此如果用户点击添加行,他们将不会丢失任何现有的编辑,我敢说这很可能会发生。
因此,我建议将此代码用于保存和添加行按钮
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
DataTable rstGrid = MyRst("SELECT * FROM People WHERE Hotel_ID = " + HotelID);
// send grid to table
GridToTable(MyGrid, rstGrid);
// save to database
SaveGrid(MyGrid, rstGrid);
}
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
DataTable rstGrid = MyRst("SELECT * FROM People where Hotel_ID = " + HotelID);
// send any data edits from Grid to table
GridToTable(MyGrid, rstGrid);
// add new row
DataRow MyNewRow = rstGrid.NewRow();
MyNewRow["Hotel_ID"] = HotelID;
rstGrid.Rows.Add(MyNewRow);
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
// save data (must do AFTER grid bind - new row!!!)
SaveGrid(MyGrid, rstGrid);
}
void SaveGrid(GridView MyGrid, DataTable rstGrid)
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(rstGrid.TableName, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
da.Update(rstGrid);
}
}
}
void GridToTable(GridView MyGrid, DataTable rstGrid)
{
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
rstData.TableName = strSQL;
}
}
return rstData;
}
Edit2:不要为 SQL 使用集中字符串?
好吧,注意是真的 - 你永远不会使用“用户输入”!!!
然而,大多数发帖者无法区分,因此有一个版本没有任何 SQL 字符串连接的 where 值。
protected void cmdView_Click(object sender, EventArgs e)
{
Button cmd = (Button)sender;
ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
GridView gChild = (GridView)gVR.FindControl("GridView2"); // pluck out the grid for this row
HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");
//if (gChild.Style["display"] == "normal")
if (MyDiv.Style["display"] == "normal")
{
// if grid is already display, then hide it, and exit
//gChild.Style["display"] = "none";
MyDiv.Style["display"] = "none";
return;
}
//gChild.Style["display"] = "normal";
MyDiv.Style["display"] = "normal";
int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];
// only re-load if never loaded
if (gChild.Rows.Count == 0)
{
SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People WHERE Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelPK;
gChild.DataSource = MyRstP(cmdSQL);
gChild.DataBind();
}
}
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People where Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
DataTable rstGrid = MyRstP(cmdSQL);
// send grid to table
GridToTable(MyGrid, rstGrid);
// save to database
SaveGrid(rstGrid,"People");
}
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
SqlCommand cmdSQL = new SqlCommand("SELECT * from People WHERE Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
DataTable rstGrid = MyRstP(cmdSQL);
// send any data edits from Grid to table
GridToTable(MyGrid, rstGrid);
// add new row
DataRow MyNewRow = rstGrid.NewRow();
MyNewRow["Hotel_ID"] = HotelID;
rstGrid.Rows.Add(MyNewRow);
// save data (must do AFTER grid bind - new row!!!)
SaveGrid(rstGrid,"People");
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
}
void SaveGrid(DataTable rstGrid, string strTable)
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM " + strTable, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
da.Update(rstGrid);
}
}
}
void GridToTable(GridView MyGrid, DataTable rstGrid)
{
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
rstData.TableName = strSQL;
}
}
return rstData;
}
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
}
我正在制作一个模块以将数组保存在 SQL 数据库中。例如,我想保存 (889,4,01/12/2021)
、(889,4,02/12/2021)
和 (889,4,03/12/2021)
.
我正在使用 gridview 获取第一个值 (889
)。然后我用文本框获取日期,然后我 运行 查询 return 行中的日期并存储在 gridview 中。
我正在尝试使用 GridView2.Rows[0].Cells[1].Text
选择第二个 gridview 值 (date
),但超出了有效值的范围。
因为这是一个数组,所以我将所有 SQL 句子保存在一个文本框中,稍后再执行,这就是我的代码
string[,] arreglo = new string[GridView1.Rows.Count, 7];
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox chkbox1 = (CheckBox)row.FindControl("chkActive");
if (chkbox1.Checked)
{
arreglo[row.RowIndex, 0] = GridView1.Rows[row.RowIndex].Cells[1].Text;
string[,] array = new string[GridView2.Rows.Count, 2];
foreach (GridViewRow col in GridView2.Rows)
array[col.RowIndex, 0] = GridView2.Rows[col.RowIndex].Cells[1].Text;
txtInsert.Text = txtInsert.Text + "insert into T_USUARIO_dETALLE(id_usuario,campana,fecha,fecha_carga,id_superv,estado_dotacion) values ('" + arreglo[row.RowIndex, 0].ToString() + "', '" + lblcampana.Text + "','"+ GridView2.Rows[0].Cells[1].Text + "','" + LBLSUPERV.Text + "','" + ddlEstado.SelectedValue + "')";
}
}
感谢帮助!!!
好的,这是 db land 中最经典的设置之一!
我们有一些父记录,对于每条记录,我们需要显示(和编辑)子行。
现在有更多 UI 口味的冰淇淋可供选择。
这表明我们需要“嵌套”主记录(比如在网格中)以显示子记录(我们的第二个网格)。
好吧,事实证明网格真的不能很好地嵌套。
因此,对于父记录,让我们使用 ListView - 它们工作得更好。
好的,所以我们可以启动向导 - 构建 LV,然后在这里使用核武器并删除 + 炸毁所有模板。在我们添加这个的同时,删除额外的嵌套 table。我算了 < 2 分钟的时间。
所以,我们现在有了这个简单的 LV。
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >
<ItemTemplate>
<tr>
<td><asp:Button ID="cmdView" runat="server" Text="+" /></td>
<td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
<td><asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' /></td>
<td><asp:Label ID="ProvinceLabel" runat="server" Text='<%# Eval("Province") %>' /></td>
<td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" class = "table table-hover" >
<tr runat="server" style="">
<th runat="server">View</th>
<th runat="server">HotelName</th>
<th runat="server">City</th>
<th runat="server">Province</th>
<th runat="server">Description</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
我们要填写的代码是这样的:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadMainGrid();
}
void LoadMainGrid()
{
string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
ListView1.DataSource = MyRst(strSQL);
ListView1.DataBind();
}
我们现在有这个:
好的,现在我们需要子网格。
然后我们将这个作为子网格移动到上面的LV中。
所以,现在我们有了这个标记:
<td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
</tr>
<tr>
<td colspan="5">
<div id="MyGrid" runat="server" style="display:none;margin-left:1%">
<div>
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover table-responsive borderhide" >
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Start date">
<ItemTemplate>
<asp:TextBox ID="dtStart" runat="server" Text='<%# Eval("dtStart", "{0:yyyy-MM-ddTHH:mm}") %>' TextMode="DateTimeLocal" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="End date">
<ItemTemplate>
<asp:TextBox ID="dtEnd" runat="server" Text='<%# Eval("dtEnd","{0:yyyy-MM-ddTHH:mm}") %>' TextMode="DateTimeLocal" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<div style="float:right;margin-right:-10px">
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" OnClick="cmdSave_Click" />
<asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" OnClick="cmdAdd_Click" />
</div>
</div>
</td>
所以我们在 lv 列的标记之后右上角。
现在,我们要做的就是连接“+”按钮展开:
这是 LV 中的第一行按钮
<td><asp:Button ID="cmdView" runat="server" Text="+" OnClick="cmdView_Click"/></td>
代码是这样的:
protected void cmdView_Click(object sender, EventArgs e)
{
Button cmd = (Button)sender;
ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
GridView gChild = (GridView)gVR.FindControl("GridView2"); // pluck out the grid for this row
HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");
//if (gChild.Style["display"] == "normal")
if (MyDiv.Style["display"] == "normal")
{
// if grid is already display, then hide it, and exit
MyDiv.Style["display"] = "none";
return;
}
MyDiv.Style["display"] = "normal";
int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];
// only re-load if never loaded
if (gChild.Rows.Count == 0)
{
gChild.DataSource = MyRst("SELECT * from People where hotel_id = " + HotelPK);
gChild.DataBind();
}
}
所以,现在我们有了这个:
好的,现在我们要做的就是创建一个“保存”按钮,用于保存我们对此 GV 所做的任何更改。
这很简单,所以我们放入一个保存按钮,如下所示:
因此,在我们的网格正下方,我们放入:
</asp:GridView>
</div>
<div style="float:right;margin-right:-10px">
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />
<asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" />
</div>
</div>
我们现在有这个:
好的,那么对于按钮,我们添加一个点击事件:
(只需输入 onclick= 并且 intelsense 会提供创建点击事件的功能,看起来什么都没发生,但是转到后面的代码,您会看到偶数存根。
我们使用这个代码:
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
// send grid to table
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT * from People WHERE hotel_id = " + HotelID;
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
DataTable rstGrid = new DataTable();
rstGrid.Load(cmdSQL.ExecuteReader());
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"]= DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
da.Update(rstGrid);
}
}
}
好的,我们不妨连接“新行按钮”。
所以对于那个代码我们有这个:
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
string strSQL = "INSERT INTO People (Hotel_ID) VALUES(" + HotelID + ")";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
cmdSQL.ExecuteNonQuery();
}
DataTable rstGrid = MyRst("SELECT * from People where Hotel_ID = " + HotelID);
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
}
}
我还有一个辅助例程 - 它是一个全局函数,对于给定的 sql 字符串,它只是 returns 数据 table。我在上面确实用过几次。
这个例程:
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
Edit/Upate(使 UI 更好):
一个问题? 如果用户点击添加新行,他们无疑会开始打字,然后很可能再次点击添加新行(但在上面,他们必须先点击保存数据)。
所以,我建议在添加新行之前保存数据。
这迫使我们无论如何都要打破那个更长的例程。
所以我们添加一个“Grid to Table”,然后添加一个“save table”到数据库。将其分成两步不仅修复了上面的“错误”或“问题”,而且实际上减少了代码。
所以,我建议更新这 3 个(以及 4 个)例程,它们都更短,应该使用。
因此,添加行、保存编辑和 MyRst 都已更新。
我建议使用此代码,因此如果用户点击添加行,他们将不会丢失任何现有的编辑,我敢说这很可能会发生。
因此,我建议将此代码用于保存和添加行按钮
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
DataTable rstGrid = MyRst("SELECT * FROM People WHERE Hotel_ID = " + HotelID);
// send grid to table
GridToTable(MyGrid, rstGrid);
// save to database
SaveGrid(MyGrid, rstGrid);
}
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
DataTable rstGrid = MyRst("SELECT * FROM People where Hotel_ID = " + HotelID);
// send any data edits from Grid to table
GridToTable(MyGrid, rstGrid);
// add new row
DataRow MyNewRow = rstGrid.NewRow();
MyNewRow["Hotel_ID"] = HotelID;
rstGrid.Rows.Add(MyNewRow);
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
// save data (must do AFTER grid bind - new row!!!)
SaveGrid(MyGrid, rstGrid);
}
void SaveGrid(GridView MyGrid, DataTable rstGrid)
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(rstGrid.TableName, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
da.Update(rstGrid);
}
}
}
void GridToTable(GridView MyGrid, DataTable rstGrid)
{
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
rstData.TableName = strSQL;
}
}
return rstData;
}
Edit2:不要为 SQL 使用集中字符串?
好吧,注意是真的 - 你永远不会使用“用户输入”!!!
然而,大多数发帖者无法区分,因此有一个版本没有任何 SQL 字符串连接的 where 值。
protected void cmdView_Click(object sender, EventArgs e)
{
Button cmd = (Button)sender;
ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
GridView gChild = (GridView)gVR.FindControl("GridView2"); // pluck out the grid for this row
HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");
//if (gChild.Style["display"] == "normal")
if (MyDiv.Style["display"] == "normal")
{
// if grid is already display, then hide it, and exit
//gChild.Style["display"] = "none";
MyDiv.Style["display"] = "none";
return;
}
//gChild.Style["display"] = "normal";
MyDiv.Style["display"] = "normal";
int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];
// only re-load if never loaded
if (gChild.Rows.Count == 0)
{
SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People WHERE Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelPK;
gChild.DataSource = MyRstP(cmdSQL);
gChild.DataBind();
}
}
protected void cmdSave_Click(object sender, EventArgs e)
{
Button cmdSave = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People where Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
DataTable rstGrid = MyRstP(cmdSQL);
// send grid to table
GridToTable(MyGrid, rstGrid);
// save to database
SaveGrid(rstGrid,"People");
}
protected void cmdAdd_Click(object sender, EventArgs e)
{
Button cmdNew = (Button)sender;
ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;
GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
SqlCommand cmdSQL = new SqlCommand("SELECT * from People WHERE Hotel_ID = @ID");
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
DataTable rstGrid = MyRstP(cmdSQL);
// send any data edits from Grid to table
GridToTable(MyGrid, rstGrid);
// add new row
DataRow MyNewRow = rstGrid.NewRow();
MyNewRow["Hotel_ID"] = HotelID;
rstGrid.Rows.Add(MyNewRow);
// save data (must do AFTER grid bind - new row!!!)
SaveGrid(rstGrid,"People");
MyGrid.DataSource = rstGrid;
MyGrid.DataBind();
}
void SaveGrid(DataTable rstGrid, string strTable)
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM " + strTable, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
da.Update(rstGrid);
}
}
}
void GridToTable(GridView MyGrid, DataTable rstGrid)
{
foreach (GridViewRow gRow in MyGrid.Rows)
{
DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
if (myDate == "")
OneRow["dtStart"] = DBNull.Value;
else
OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
if (myDate == "")
OneRow["dtEnd"] = DBNull.Value;
else
OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
rstData.TableName = strSQL;
}
}
return rstData;
}
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
}