我在 C# 中使用 ASP.NET Web 表单
我有一个 GridView,其中包含可用房间列表,每个房间旁边的列中都有一个“预订”按钮。单击“保留”时,我希望创建一个 Room 类 selectedRoom 的对象,该对象包含与 availableRooms 列表中的信息相同的信息。
availableRooms 列表是在这些方法之外的 WebForms 方法中初始化的。
这是我的 BtnSearch_Click 方法的片段,它实际上成功地在页面上显示了 GridView:
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Room room = new Room();
room.roomID = reader.GetInt32("roomID");
room.roomName = reader.GetString("roomName");
room.roomType = reader.GetString("typeName");
room.enSuite = reader.GetBoolean("enSuite");
room.ppNight = reader.GetFloat("pricePerNight");
if (!reader.IsDBNull(reader.GetOrdinal("ppAddAdult")))
{
room.ppAddAdult = reader.GetFloat("ppAddAdult");
}
else
{
room.ppAddAdult = 0.0f;
//allows null value
}
if (!reader.IsDBNull(reader.GetOrdinal("ppAddChild")))
{
room.ppAddChild = reader.GetFloat("ppAddChild");
}
else
{
room.ppAddChild = 0.0f;
//allows null values
}
TimeSpan lengthStay = checkOutDate - checkInDate;
//calculate length of stay
room.lengthStay = (int)lengthStay.TotalDays;
room.price = room.GetPrice(Convert.ToInt32(adultGuests.Text), Convert.ToInt32(childGuests.Text));
//calculate price
availableRooms.Add(room);
//add current room to list
}
}
}
catch (Exception ex)
{
error = Convert.ToString(ex);
}
}
gridViewRooms.DataSource = availableRooms;
gridViewRooms.DataBind();
//provide data source and bind data for gridView
这是我的保留按钮逻辑的片段:
protected void gridViewRooms_reserveCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Reserve")
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
try
{
connection.Open();
int accountID = 0;
DateTime checkOutDate = Convert.ToDateTime(checkOut.Text);
DateTime checkInDate = Convert.ToDateTime(checkIn.Text);
//initalise variables
int rowID = Convert.ToInt32(e.CommandArgument);
Room selectedRoom = availableRooms.Find(room => room.roomID == rowID);
//define the currently selected room
令我困惑的是,availableRooms 列表在页面上完美显示,但当我单击“Reserve”时突然变为空,从而阻止了 selectedRoom 的创建。
我尝试通过再次调用 BtnSearch_Click 方法来重新填充 availableRooms 列表,但它产生了很多很多错误。任何帮助将不胜感激 - 我对此很陌生。谢谢。
我不会费心使用 GridView 中内置的命令“system”(它们很混乱,而且没有多大帮助——真的,它们没有!!!)。
但是,无论哪种方式(标准的简单按钮和按钮单击),还是使用 GridView 的命令)?
您需要获取给定的单击行,然后必须使用 find.control 来获取/拉动/查看/使用给定 GirdView 行的控件。
因此,您需要当前的GridViewRow。然后使用 .findcontrol 方法。
不清楚您发布的代码为何/如何编译,但使用
room.roomID
这是 GridView 上的有效控件(我假设),但是 GridView 中的那些模板化控件每行都有许多这些控件的实例。
因此,您必须提取当前行的 room.id 值(控件)。
(或者在您的情况下更好地拉动组合框控件)。
事实上,对于主键值(数据库 PK)之类的东西,我不建议在 GridView 标记中包含 PK 值(这是一个很大的安全风险,您可以为此目的使用数据密钥)。这意味着您不必在 GridView 标记中包含数据库 PK 列值。
好的,所以你必须先获取当前行。
然后获取/抓取 GridView 的一行的给定控件的实例。
如果用户更改/选择房间类型,如果您没有将其保存回数据库,那么通过数据库“房间类型 id”查找/获取/使用房间类型的代码将无法工作,除非您将数据行保存回来每次用户更改房间类型时都会记录到数据库。
现在,如果这样的房间更改与该组合总是强制更新数据库,那么您的房间类型查找代码应该可以工作。
但是,如果用户可以自由更改房型组合而你不保存回数据库呢?
然后如上所述,应使用当前 GridView 行的值。
因此,要从当前行中提取/获取值,则:
网格中的按钮标记可以是这样的:
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button1" runat="server" Text="Row Click"
CommandName="RowClick"
CommandArgument='<%# Eval("ID") %>'
/>
</ItemTemplate>
</asp:TemplateField>
Rowcommand 可以是这样的:
protected void GVHotels_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "RowClick")
{
Button btn = (Button)e.CommandSource;
GridViewRow gRow = (GridViewRow)btn.NamingContainer;
Debug.Print($"Row index = {gRow.RowIndex}");
int PK = (int)GVHotels.DataKeys[gRow.RowIndex]["ID"];
Debug.Print($"Database PK = {PK}");
CheckBox chkSel = (CheckBox)gRow.FindControl("chkSel");
Debug.Print($"Check box setting = {chkSel.Checked}");
}
}
因此,就我而言,当前行上有一个复选框。
例如这个:
所以,我在那一行的复选框是这样的:
<asp:TemplateField
ItemStyle-HorizontalAlign="Center"
HeaderStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:CheckBox ID="chkSel" runat="server"
OnCheckedChanged="chkSel_CheckedChanged"
AutoPostBack="true" />
</ItemTemplate>
</asp:TemplateField>
如前所述,我们不必在这里使用“命令”,而只需一个简单的按钮。
因此,在您的标记中,使用如下按钮:
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdRowBtn" runat="server" Text="Row Click"
CommandArgument='<%# Eval("ID") %>'
OnClick="cmdRowBtn_Click"
/>
</ItemTemplate>
</asp:TemplateField>
然后我们的按钮代码就变成这样了:
protected void cmdRowBtn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
GridViewRow gRow = (GridViewRow)btn.NamingContainer;
Debug.Print($"Row index = {gRow.RowIndex}");
int PK = (int)GVHotels.DataKeys[gRow.RowIndex]["ID"];
Debug.Print($"Database PK = {PK}");
CheckBox chkSel = (CheckBox)gRow.FindControl("chkSel");
Debug.Print($"Check box setting = {chkSel.Checked}");
}
如果您愿意,您仍然可以使用上面的“CommandArgs”。
因此,可以使用给定控件的任何标准事件。因此,您可以使用“NamingContainer”选取当前行。这适用于点击事件,甚至是下拉选择的索引更改事件或其他事件。
如上面 2 个示例所示,一旦我们掌握了当前的 GridViewRow,那么我们就必须使用该给定行的 .findcontrol() 方法。
对于非模板化列,您可以使用 GridViewRow 的 .cells[] 集合;对于模板化列,您必须使用 .findcontrol。我认为在你的情况下你想要 RoomType。 (但不确定 GridView 中的控件是什么。我想您可以“基于 PK 走回数据库,假设组合始终更新数据库。如果不是,那么您需要从 GridView 中提取,而不是从数据库中提取,因为您是。
因此,在您的情况下,获取当前行,然后使用 .findcontrol 方法获取给定的控件,然后您可以自由使用/获取所需控件的 .text 值,甚至选定的索引或其他内容.