太好了。好的,我们不必太担心搜索部分——我假设你输入了一些搜索,带有参数,结果是一个数据表。
现在,我强烈建议您考虑使用列表视图代替网格视图。
至于控制哪些列?好吧,您可以对每一列进行模板化。 (这就是为什么我建议使用列表视图 - 它的标记更少)。
但是,我没有太多的列 - 所以 GV 是“好的”,但是如果你想要更多的列,更多的自定义布局 - 那么 LV 将是 LESS 标记。
LV 的另一个真正大的优势是你可以让它为你编写标记。
不管怎样,好吧,这是我们的 GV。
非常重要:
每行都有一个 PK 主键(“ID”)。我们当然不想显示或显示那个 PK ID,但众所周知,PK 是任何数据系统的命脉。因此,GV 中有一个非常酷的功能——称为 DataKeys。它允许您使用/拥有/播放 PK 行 ID,但您不必在 GV 中公开或显示它。 (所以不仅从 UI 的角度来看很好,从安全的角度来看也非常好)。
所以,假设我们有这个 GV 布局:
<div style="width:40%;padding:25px">
<style> .borderhide input {border:none}</style>
<asp:GridView ID="GVPeople" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" cssclass="table borderhide">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="Active" runat="server"
Checked='<%# Eval("Active") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hotel ID">
<ItemTemplate>
<asp:TextBox ID="Hotel_ID" runat="server" Text='<%# Eval("Hotel_ID") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
我们会通过数据感受这个 GV - 存在更多列 - 但我们不在乎。
所以,到目前为止我的代码是这样的:
Dim rstData As New DataTable
Dim rstHotels As New DataTable ' for combo box
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid()
ViewState("rstData") = rstData
Else
rstData = ViewState("rstData")
End If
End Sub
Sub LoadGrid()
rstHotels = MyRst("SELECT ID, HotelName from tblHotels ORDER BY HotelName")
rstData = MyRst("SELECT * from People Order by FirstName")
GVPeople.DataSource = rstData
GVPeople.DataBind()
End Sub
所以现在我们有了这个:
好的,所以您的问题之一是我们显然不想显示 Hotel_id,而是想将其翻译成描述。当然,如果我们要允许编辑,那么让我们将 Hotel_ID 转换为组合框(下拉列表)。和大多数/所有组合框一样,我们将存储酒店的 PK id,但当然显示酒店名称以方便使用。
所以,代替hotel_id,我们将标记更改为:
<asp:TemplateField HeaderText="Hotel ID">
<ItemTemplate>
<asp:DropDownList ID="cboHotel" runat="server"
DataTextField="HotelName"
DataValueField="ID">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
好的,现在我们必须填充 + 设置组合框。我们有两个任务:
用数据源填充组合框
将组合框设置为每个 gv 行的当前选择。
为此,我们将使用 GV 行数据绑定事件。
所以,我们填写组合的代码如下所示:
所以我们有这个代码:
Protected Sub GVPeople_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GVPeople.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
' get full row of data bind - all columns
Dim gData As DataRowView = e.Row.DataItem ' NOT A GRID VIEW ROW!!!!!
' get combo box
Dim cboHotels As DropDownList = e.Row.FindControl("cboHotel")
' setup cbo data source
cboHotels.DataSource = rstHotels
cboHotels.DataBind()
cboHotels.Items.Insert(0, New ListItem("", "")) ' add blank (no choice)
If IsDBNull(gData("Hotel_id")) = False Then
cboHotels.SelectedValue = gData("Hotel_ID").ToString
End If
End If
End Sub
所以,现在我们的结果是这样的:
好的,这样就可以解决您的一个问题/问题。
接下来是编辑 - 这真的很酷,也很简单。
好的,如果您仔细观察,我会“隐藏”文本框的边框,但您现在发现您可以像 Excel 一样使用 Tab 键。一个不错的免费蜜蜂是当文本框有焦点时,它们会显示!!
因此,让我们将我们的按钮放在网格下方以保存编辑。当我点击时它看起来像这样:
很像魔术 - 您现在可以使用标签 - 几乎就像 Excel。并且您可以选择组合框的值。
在上面,我们在 GV 下方放置了一个简单的按钮,如下所示:
</asp:GridView>
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />
好的,现在是保存数据按钮。
我们将编写一个辅助例程。将此代码拆分为两个例程的原因有很多。那么第一个套路呢?
它将网格值发送回我们的表。如果仔细观察,我会将 GV 表数据源持久化为 rstData。
所以这个例程将网格发送回表格。
Sub GridToTable()
' pull GV rows back to table.
For Each gRow As GridViewRow In GVPeople.Rows
' Get database PK value
Dim PK As Integer = GVPeople.DataKeys(gRow.RowIndex).Item("ID")
Dim OneDataRow As DataRow = rstData.Select("id = " & PK)(0)
OneDataRow.Item("FirstName") = CType(gRow.FindControl("FirstName"), TextBox).Text
OneDataRow.Item("LastName") = CType(gRow.FindControl("LastName"), TextBox).Text
OneDataRow.Item("City") = CType(gRow.FindControl("City"), TextBox).Text
OneDataRow.Item("Active") = CType(gRow.FindControl("Active"), CheckBox).Checked
' combo box
Dim cboHotel As DropDownList = gRow.FindControl("cboHotel")
If cboHotel.Text = "" Then
OneDataRow("Hotel_ID") = DBNull.Value
Else
OneDataRow("Hotel_ID") = cboHotel.SelectedItem.Value
End If
Next
End Sub
好的,所以现在我们要做的就是发送 rstData 表(并得到这个:这将处理新行或编辑!!!!)。
所以,现在我们的保存按钮代码如下所示:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
GridToTable()
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)
Dim da As New SqlDataAdapter(cmdSQL)
Dim daC As New SqlCommandBuilder(da)
conn.Open()
da.Update(rstData)
End Using
End Using
End Sub
所以请注意我们如何将整个网格发送回数据库,以及一次拍摄中的所有更改。
最后但并非最不重要的一点:
我使用了一个辅助例程来获取一个数据表(一遍又一遍地键入那种代码变得非常快速,所以我有了这个并将其设置为对整个应用程序都是全局的:
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
rstData.TableName = strSQL
End Using
End Using
Return rstData
End Function
注意非常小心,我还将 sql 语句填充到 rst.Table 名称中。表名并没有真正使用,但现在因为我为该表保留了 SQL?
那么其实就是这一行
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)
变成:
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(rstData.TableName, conn)
这意味着如果/当我说要在页面上编辑子母版或多个数据表时?我使用一个数据集(表的集合),并有一个 routien 一次性将所有表和所有编辑发送回数据库。我们没有超过一个数据表要编辑,但这解释了为什么我将 SQL 语句推入数据表“表”名称,因为如您所见,我们甚至不必重新输入使用的sql。
请注意:
我使用的那个sql语句:
SELECT * from People WHERE ID = 0
不是类型-o。我用它来让 sqlCommandBuilder 为我完成所有繁琐的连接和创建 sql 插入和更新流的工作。