asp:GridView 允许“编辑”按钮,但删除“更新”和“取消”按钮

asp:GridView allow Edit button, but remove Update and Cancel buttons

这个非常简单。 asp:GridView 会自动在每一列的左侧添加一个编辑超链接,如下所示:

这很好,因为无论如何我都需要该功能。但是,我已经做到了,因此单击“编辑”超链接会弹出一个新面板,允许用户编辑比 GridView 中显示的更多的属性,因此我不希望在单击“编辑”后出现“更新”和“取消”按钮。

我通过实现一个事件处理程序来添加编辑功能,该事件处理程序在 e.CommandName =“编辑”时处理 GridView.RowCommand。我只想将“编辑”超链接保留在那里,或者以编程方式单击“取消”,或者当用户完成使用“编辑”面板时,任何可以防止更新和取消超链接显示的东西。我试过调用事件处理程序并使用 e.CommandName = "Cancel" 发送 args 但这没有用。

我愿意探索的另一个选择是完全删除编辑按钮并让我的事件处理程序处理不同的事件,但我也没有找到任何好的资源。大多数情况下,人们试图禁用他们在某些行上手动创建的编辑按钮。不过,我没有创建此“编辑”超链接,而且我无法让它消失。

嗯,既然你弹出了一个面板?然后转储整个模板和自动编辑系统。真的,为了快速和肮脏 - 那些内置的 GV 事件非常适合让你起来 运行。

但是,一旦您真正掌握了这一切的工作原理,结果会怎样?您可以通过这种方式纯编码,您甚至可以得到更少的代码和更少的标记,而且麻烦更少!!!

事实上,您甚至可以转储整个 GV“行”处理程序 - 因为它不会再对您有任何帮助。

事实上,更好?只需放入平面简编辑按钮 - 即使是 asp.net 按钮。您真的不需要更多! - 并且你经常会得到更少混乱的代码。真的很棒吗?好吧,您添加到 GV 的每个按钮都有自己的点击事件 - 它自己的按钮点击和它自己的按钮点击 - 与您刚刚放入 GV 的任何其他控件或按钮非常相似。

事实上,如果问题是如何像 Excel 那样切换和编辑 gv,我可以 post 一个非常简短、简单的解决方案,并且 NONE 它使用GV 的内置事件。

但是,让我们概述一下它是如何工作的,并使用“最少”的代码。

你没有提到你在这里使用的是哪种“对话框”(而且有很多,范围从 jquery.UI(我将使用),甚至来自 ajaxtoolkit 的对话框也是很好。

所以,我会说我不喜欢建议引入“再多一个”JavaScript 库。但是,几乎可以肯定,您默认安装了 jQuery。所以,添加 jquery.UI 没什么大不了的。

所以,我们的目标:

Dump the messy GV event model.
STILL use + write as much as possible easy server side code.
Write and use a absolute min of JavaScript code.

现在,我将使用我在 vb.net 中编写的一些辅助例程。它们很短,易于使用。我很快厌倦了一遍又一遍地编写相同的代码:

Shuffle data from data table to some controls for edit
Shuffle data from controls back to table, and then save table to database.

但是,即使没有上面的“随机播放 to/from”例程,您会发现通过实际转储 GV 事件,这段代码的麻烦要少得多。

好的,让我们假设一个简单的酒店网格。在每一行,我们想要一个编辑按钮。

所以,第一个简单的部分,这是我们的网格:

    <div style="width:40%">
        <asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ID" CssClass="table">
            <Columns>
                <asp:BoundField DataField="FirstName" HeaderText="FirstName"  />
                <asp:BoundField DataField="LastName" HeaderText="LastName"    />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName"  />
                <asp:BoundField DataField="Description" HeaderText="Description"  />
                <asp:TemplateField HeaderText="Edit">
                    <ItemTemplate>
                        <asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn" OnClick="cmdEdit_Click" />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </div>

一些仅供参考:是的,为了节省时间,我确实使用了上面的向导来创建。然后我吹出 datasource1 和 gv 的数据源设置。并且我从每一行的显示中删除了“ID”。注意非常小心 - PK 行“id”设置现在是这样的:

DataKeyNames="ID"

这是一个很棒的功能,因为它将维护、使用并允许您轻松获取 PK 行 ID,但不必在标记中公开它 - 代码更少,最好永远不要向用户显示 PK 内容.

并注意我是如何设置 CssClass="table" 的。别担心,但这样做会 bootstrap GV - 而且它看起来好多了。 (并且它还会自动 expands/grows 到 div 宽度大小 - 试试这个 - 因为默认安装 bootstrap)。

现在我们的代码是这样的: (别担心 - 我会包含此处使用的所有代码)。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid
    End If

End Sub

Sub LoadGrid()

    Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA ORDER BY HotelName")
    GHotels.DataSource = MyrstP(cmdSQL)
    GHotels.DataBind()

End Sub

现在我们有了这个:

到目前为止,真的很简单。

现在,不清楚您使用什么进行编辑(您的弹出窗口),但我们需要“某种”弹出系统。所以,我会选择 jquery.UI。它工作得相当好 - 比尝试让 bootstrap 对话框工作要好得多。

所以,在GV之后,我们需要布局+做一个“一行”的编辑器。 (并将其放在 div 中)。所以,这看起来非常适合这个目的:(在开发过程中,我没有设置 display:none,但是一旦你看起来不错,然后为 div 样式设置 display:none - 那隐藏它(jquery.ui 然后处理这个)。

好的,我们的“编辑详细信息div”就不多说了。我在 GV 之后就放弃了 htis。

所以,我们有这个:

    <div id="EditRecord" runat="server" style="float:left;display: none">
        <style>
            .iForm label {display:inline-block;width:90px}
            .iForm input {border-radius:8px;border-width:1px;margin-bottom:10px}                
            .iForm textarea {border-radius:8px;border-width:1px;margin-bottom:10px}     
            .iForm input[type=checkbox] {margin-right:8px}
        </style>

        <div style="float:left" class="iForm">
                <label>HotelName</label><asp:TextBox ID="txtHotel" runat="server" f="HOtelName" width="280"></asp:TextBox> <br />
                <label>First Name</label><asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />
                <label>Last Name</label><asp:TextBox ID="tLN" runat="server" f="LastName" Width="140"></asp:TextBox> <br />
                <label>City</label><asp:TextBox ID="tCity" runat="server" f="City" Width="140"></asp:TextBox> <br />
                <label>Province</label><asp:TextBox ID="tProvince" runat="server" f="Province" Width="75"></asp:TextBox> <br />
        </div>
        <div style="float:left;margin-left:20px" class="iForm">
            <label>Description</label> <br />
            <asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine" 
                Height="150px" f="Description" ></asp:TextBox> <br />
            <asp:CheckBox ID="chkActive" f="Active" Text=" Active" runat="server" TextAlign="Right" />
            <asp:CheckBox ID="chkBalcony" f="Balcony" Text=" Has Balcony" runat="server" TextAlign="Right" />
        </div>
        <div style="clear:both"></div>
        <button id="cmdSave" runat="server" class="btn" onserverclick="cmdSave_ServerClick" >
            <span aria-hidden="true" class="glyphicon glyphicon-floppy-saved"> Save</span> 
        </button>

        <button id="cmdCancel" runat="server" class="btn" style="margin-left:15px">
            <span aria-hidden="true" class="glyphicon glyphicon-arrow-left"> Back/Cancel</span>
        </button>

        <button id="cmdDelete" runat="server" class="btn" style="margin-left:15px">
            <span aria-hidden="true" class="glyphicon glyphicon-trash"> Delete</span>
        </button>
   </div>

现在我们 JavaScript 的一位 - 但这就是我们要写的全部内容:

在上面 div:

之后删除它
    <script>
        function PopEdit() {
            var myDialog = $("#EditRecord");
            myDialog.dialog({
                title: "Edit Hotel Information",
                modal: true,
                width: 860,
                appendTo: "form"
            });
        }
    </script>

好了,就这些了。

现在,我们点击了该行按钮。如前所述,这只是一个平面简 asp.net 按钮,或您喜欢的任何按钮。

GV 中的那个按钮是这样的:

<asp:TemplateField HeaderText="Edit">
   <ItemTemplate>
     <asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn" OnClick="cmdEdit_Click" />
   </ItemTemplate>
</asp:TemplateField>

以及此按钮的代码:

Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)

    Dim btn As Button = sender
    Dim gRow As GridViewRow = btn.NamingContainer
    Dim pkID = GHotels.DataKeys(gRow.RowIndex).Item("ID")

    Dim cmdSQL As New SqlCommand("SELECT * from tblHotelsA where ID = @ID")
    cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = pkID
    Dim rstData As DataTable = MyrstP(cmdSQL)

    Call fLoader(Me.EditRecord, rstData.Rows(0))
    ViewState("rstData") = rstData
    ClientScript.RegisterStartupScript(Page.GetType(), "PopEditKey", "PopEdit()", True)

End Sub

代码不多。我们简单地加载我们的“div”,然后用 jquery.UI 位代码弹出它。

结果现在是这样的:

好的,现在我们需要保存按钮代码。就是这样:

Protected Sub cmdSave_ServerClick(sender As Object, e As EventArgs)

    Dim rstData As DataTable = ViewState("rstData")
    Call fWriterW(EditRecord, rstData.Rows(0))
    Call SaveTable(rstData, "tblHotelsA")
    LoadGrid()

End Sub

还有 cancel/back 按钮?我们知道任何 post-back 都会关闭对话框,所以它实际上不需要太多代码。如果你愿意,我可以 post 删除按钮的代码(我们可能应该提供一个漂亮的“确认”删除提示 - 我们可以为此使用 jQuery.Ui 对话框 - 但同样,使用 90% 服务器端清理 vb 删除按钮代码。

好的,现在是我在上面使用的辅助例程。

我有 3 个

 MyRstP - this just accepts a sql command - retruns a table.

Public Function MyrstP(sqlCmd As SqlCommand) As DataTable

    Dim rstData As New DataTable
    Using sqlCmd
        Using conn = New SqlConnection(My.Settings.TEST4)
            conn.Open()
            sqlCmd.Connection = conn
            rstData.Load(sqlCmd.ExecuteReader)
        End Using
    End Using
    Return rstData

End Function

以上只是省去了“一遍又一遍”的麻烦哈正在编写查询代码。

然后我们有一个名为“fLoader”的例程。再一次,一遍又一遍地编写只需要一个数据行并将其推到窗体上的控件的代码变得非常累人。因此,对于“div”中的每个控件,我只是组成了自己的“标签”。我使用 f="data base column name goes here"

因此,在给定的 div 内,您会看到酒店名称:

<label>HotelName</label><asp:TextBox ID="txtHotel" runat="server" f="HotelName" width="280"></asp:TextBox> <br />
<label>First Name</label><asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />

因此,对于每个控件,我都编写了自己的绑定 - 省去了您必须一遍又一遍地编写该代码。

所以,floader 看起来像这样(我刚刚在 mycode 中添加了一个 module1)。因此所有表单和例程都可以使用此代码。它所做的只是获取 rstData (row(0),并将数据库列移动到具有标记 f="列名" 的控件。这是一些代码,但在编写它之后,它肯定会推送数据控制起来相当容易。

Public Sub fLoader(F As HtmlGenericControl, rst As DataRow)

    For Each c As System.Web.UI.Control In F.Controls
        Select Case c.GetType
            Case GetType(TextBox)
                Dim ctlC As TextBox = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
                    End If
                End If
            Case GetType(Label)
                Dim ctlC As Label = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
                    End If
                End If
            Case GetType(DropDownList)
                Dim ctlC As DropDownList = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
                    End If
                End If
            Case GetType(CheckBox)
                Dim ctlC As CheckBox = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        ctlC.Checked = rst(ctlC.Attributes("f"))
                    End If
                End If
            Case GetType(RadioButtonList)
                Dim ctlC As RadioButtonList = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        ctlC.SelectedValue = rst(ctlC.Attributes("f"))
                    End If
                End If
        End Select
    Next

End Sub

然后我就反过来了。从控件中获取 -> 返回到 rstData(数据行,但来自数据table)。

确实是上面的代码“反向”,从控件和推中获取值,然后返回到 rstData。

Public Sub fWriterW(f As HtmlGenericControl, rst As DataRow)

    For Each c As System.Web.UI.Control In f.Controls
        Select Case c.GetType
            Case GetType(TextBox)
                Dim ctlC As TextBox = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
                    End If
                End If
            Case GetType(Label)
                Dim ctlC As Label = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
                    End If
                End If
            Case GetType(DropDownList)
                Dim ctlC As DropDownList = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
                    End If
                End If
            Case GetType(CheckBox)
                Dim ctlC As CheckBox = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        rst(ctlC.Attributes("f")) = ctlC.Checked
                    End If
                End If

            Case GetType(RadioButtonList)
                Dim ctlC As RadioButtonList = c
                If Not ctlC.Attributes("f") Is Nothing Then
                    If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
                        rst(ctlC.Attributes("f")) = ctlC.SelectedValue
                    End If
                End If


        End Select
    Next

End Sub

然后还有一个例程 - 这个例程只是将数据库 table BACK 保存到数据库。因此,您将 rstData 和 table 名称传递给它。

Sub SaveTable(rstData As DataTable, strTable As String)

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand("select * FROM " & strTable, conn)
            Dim da As New SqlDataAdapter(cmdSQL)
            Dim daU As New SqlCommandBuilder(da)
            conn.Open()
            da.Update(rstData)
        End Using
    End Using

End Sub

所以,那些小的辅助例程 - 我只是放在平面 jane 模块中,因此我的所有代码都可以使用它。这真的很好,因为你真的不会弄乱太多 sql,而且永远不必弄乱一大堆参数。

公平地说,我可以post编辑一个网格行按钮代码。请注意它是如何成为一个简单的常规按钮 - 并且不使用 GV 事件 - 但它是服务器端代码的平面简“点击”事件。并仔细查看代码 - 注意它如何获取单击的行,以及它如何获取 PK ID。