【问题标题】:ASP.NET Webforms nested Gridview click on parent gridview row does not show child gridviewASP.NET Webforms嵌套Gridview单击父gridview行不显示子gridview
【发布时间】:2021-08-30 13:02:39
【问题描述】:

我正在尝试使用嵌套的 gridview 构建一个 webforms 应用程序。问题是当我单击父网格视图中一行的“+”时没有任何反应。见下文:

我有以下代码。

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Add Bill of Materials</h2>

    <script type="text/javascript">
        $(document).ready(function () {
            window.setTimeout(function () {
                $(".alert").fadeTo(1500, 0).slideUp(500, function () {
                    $(this).remove();
                });
            }, 3000);
        });

        function divexpandcollapse(divname) {
            var img = "img" + divname;
            if ($("#" + img).attr("src") == "../../Images/plus.png") {
                $("#" + img)
                    .closest("tr")
                    .after("<tr><td></td><td colspan = '100%' > " + $("#" + divname)
                        .html() + "</td></tr>")
                $("#" + img).attr("src", "../../Images/minus.png");
            } else {
                $("#" + img).closest("tr").next().remove();
                $("#" + img).attr("src", "../../Images/plus.png");
            }
        }
    </script>

    <div runat="server" visible="false" id="AlertDanger" class="alert alert-danger">
        <a href="#" class="close" data-dismiss="alert">&times;</a>BMDetails
        <strong>You must choose a date</strong>
    </div>

    <div runat="server" visible="false" id="AlertSuccess" class="alert alert-success">
        <a href="#" class="close" data-dismiss="alert">&times;</a>
        <strong>Purchase requisition saved successfully</strong>
    </div>
    <asp:Panel ID="BMDetails" runat="server">
        <div>
            <asp:UpdatePanel ID="UpdatePanelBM" runat="server">
                <ContentTemplate>
                    <fieldset class="form-horizontal">
                        <div class="row">
                            <div class="control-group col-sm-4">
                                <asp:Label runat="server" CssClass="col-sm-6 control-label" Style="text-align: left">Doc No.</asp:Label>
                                <div class="form-group col-sm-6">
                                    <asp:Label ID="lblDocNum" runat="server" CssClass="form-control" BackColor="#E6E6E6"></asp:Label>
                                </div>
                            </div>
                            <div class="control-group col-sm-8">
                                <asp:Label runat="server" CssClass="col-sm-6 control-label">Cust. PO No.</asp:Label>
                                <div class="form-group col-sm-6">
                                    <asp:TextBox ID="txtPurchaseDocNum" runat="server" AutoPostBack="true" CssClass="form-control" OnTextChanged="txtPurchaseDocNum_TextChanged"></asp:TextBox>
                                    <ajaxToolkit:AutoCompleteExtender
                                        ID="AutoCompleteExtender1"
                                        runat="server"
                                        TargetControlID="txtPurchaseDocNum"
                                        ServicePath="../../Web_Service/PurchaseOrders.asmx"
                                        ServiceMethod="GetPurchaseOrders"
                                        MinimumPrefixLength="2"
                                        EnableCaching="true"
                                        CompletionSetCount="10"
                                        CompletionInterval="10"
                                        DelimiterCharacters=";, :"
                                        ShowOnlyCurrentWordInCompletionListItem="true">
                                    </ajaxToolkit:AutoCompleteExtender>
                                    <asp:RequiredFieldValidator runat="server" ControlToValidate="txtPurchaseDocNum" Display="Dynamic"
                                        CssClass="text-danger" ErrorMessage="The Cust. Purchase Order No field is required." />
                                </div>
                            </div>
                        </div>
                    </fieldset>
                    <asp:GridView ID="bMGridView"
                        runat="server"
                        AutoGenerateColumns="False"
                        AllowPaging="True"
                        AllowSorting="True"
                        ShowFooter="True"
                        OnPageIndexChanging="bMParentGrid_PageIndexChanging"
                        OnRowDataBound="bMParentGrid_RowDataBound"
                        OnRowCommand="bMParentGrid_RowCommand"
                        PagerStyle-CssClass="bs-pagination"
                        ShowHeaderWhenEmpty="True"
                        EmptyDataText="Select Customer PO number"
                        CssClass="table table-striped table-bordered table-hover table-condensed">
                        <Columns>                           
                            <asp:TemplateField ItemStyle-Width="20px">
                                <ItemTemplate>
                                    <a href="JavaScript:divexpandcollapse
                                    ('div<%# Eval("Item") %>');">
                                        <img alt="Details" id="imgdiv<%# Eval
                                        ("Item") %>"
                                            src="../../Images/plus.png" />
                                    </a>                                    
                                    <div id="div<%# Eval("Item") %>" style="display: none;">                                       
                                        <asp:GridView ID="bMChildGrid"
                                            runat="server"
                                            AutoGenerateColumns="False"
                                            AllowPaging="True"
                                            AllowSorting="True"
                                            ShowFooter="True"
                                            OnRowEditing="bMChildGrid_RowEditing"
                                            OnRowCancelingEdit="bMChildGrid_RowCancelingEdit"
                                            OnRowUpdating="bMChildGrid_RowUpdating"
                                            PagerStyle-CssClass="bs-pagination"
                                            ShowHeaderWhenEmpty="True"
                                            EmptyDataText="No Records Found"
                                            CssClass="table table-striped table-bordered table-hover table-condensed">
                                            <Columns>
                                                <asp:TemplateField ItemStyle-Width="30px" HeaderText="#">
                                                    <ItemTemplate>
                                                        <asp:Label ID="lblLineNum" Text='<%# Container.DataItemIndex + 1 %>' runat="server" />
                                                    </ItemTemplate>
                                                </asp:TemplateField>
                                                <asp:TemplateField ItemStyle-Width="500px" HeaderText="Item">
                                                    <ItemTemplate>
                                                        <asp:Label ID="lblItem" runat="server"
                                                            Text='<%# Bind("Item")%>'></asp:Label>
                                                    </ItemTemplate>
                                                    <EditItemTemplate>
                                                        <asp:TextBox ID="txtItem" runat="server" Width="500px" Text='<%# Bind("Item")%>'></asp:TextBox>
                                                        <ajaxToolkit:AutoCompleteExtender
                                                            ID="AutoCompleteExtender3"
                                                            runat="server"
                                                            TargetControlID="txtItem"
                                                            ServicePath="../../Web_Service/Items.asmx"
                                                            ServiceMethod="GetItems"
                                                            MinimumPrefixLength="2"
                                                            EnableCaching="true"
                                                            CompletionSetCount="10"
                                                            CompletionInterval="10"
                                                            DelimiterCharacters=";, :"
                                                            ShowOnlyCurrentWordInCompletionListItem="true">
                                                        </ajaxToolkit:AutoCompleteExtender>
                                                        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtItem" Display="Dynamic" ValidationGroup="Edit"
                                                            CssClass="text-danger" ErrorMessage="The Item field is required." />
                                                    </EditItemTemplate>
                                                    <FooterTemplate>
                                                        <asp:TextBox ID="txtItem" runat="server" Width="500px"></asp:TextBox>
                                                        <ajaxToolkit:AutoCompleteExtender
                                                            ID="AutoCompleteExtender4"
                                                            runat="server"
                                                            TargetControlID="txtItem"
                                                            ServicePath="../../Web_Service/Items.asmx"
                                                            ServiceMethod="GetItems"
                                                            MinimumPrefixLength="2"
                                                            EnableCaching="true"
                                                            CompletionSetCount="10"
                                                            CompletionInterval="10"
                                                            DelimiterCharacters=";, :"
                                                            ShowOnlyCurrentWordInCompletionListItem="true">
                                                        </ajaxToolkit:AutoCompleteExtender>
                                                        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtItem" Display="Dynamic" ValidationGroup="Insert"
                                                            CssClass="text-danger" InitialValue="-1" ErrorMessage="The Item field is required." />
                                                    </FooterTemplate>
                                                </asp:TemplateField>
                                                <asp:TemplateField ItemStyle-Width="120px" HeaderText="Required Qty.">
                                                    <ItemTemplate>
                                                        <asp:Label ID="lblQuantity" runat="server"
                                                            Text='<%# Bind("Quantity")%>'></asp:Label>
                                                    </ItemTemplate>
                                                    <EditItemTemplate>
                                                        <asp:TextBox ID="txtQuantity" runat="server" Width="100px"
                                                            Text='<%# Bind("Quantity")%>'></asp:TextBox>
                                                        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtQuantity" Display="Dynamic" ValidationGroup="Edit"
                                                            CssClass="text-danger" ErrorMessage="The Quantity field is required." />
                                                        <asp:RegularExpressionValidator ControlToValidate="txtQuantity" runat="server" CssClass="text-danger" Display="Dynamic"
                                                            ErrorMessage="Only integers allowed." ValidationExpression="^(0|[1-9]\d*)$"
                                                            ValidationGroup="Edit"></asp:RegularExpressionValidator>
                                                    </EditItemTemplate>
                                                    <FooterTemplate>
                                                        <asp:TextBox ID="txtQuantity" runat="server" Width="100px"></asp:TextBox>
                                                        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtQuantity" Display="Dynamic" ValidationGroup="Insert"
                                                            CssClass="text-danger" ErrorMessage="The Quantity field is required." />
                                                        <asp:RegularExpressionValidator ControlToValidate="txtQuantity" runat="server" CssClass="text-danger" Display="Dynamic"
                                                            ErrorMessage="Only integers allowed." ValidationExpression="^(0|[1-9]\d*)$"
                                                            ValidationGroup="Insert"></asp:RegularExpressionValidator>
                                                    </FooterTemplate>
                                                </asp:TemplateField>
                                            </Columns>
                                        </asp:GridView>
                                    </div>
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField ItemStyle-Width="30px" HeaderText="#">
                                <ItemTemplate>
                                    <asp:Label ID="lblLineNum" Text='<%# Container.DataItemIndex + 1 %>' runat="server" />
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:BoundField DataField="Item" HeaderText="Item" />
                            <asp:BoundField DataField="Quantity" HeaderText="Quantity" />

                        </Columns>
                    </asp:GridView>

                    <div class="form-group">
                        <div class="row">
                            <div class="col-sm-3">
                                <asp:Button runat="server" ID="InsertButton" OnClick="Insert" Text="Add" CssClass="btn btn-block btn-primary" />
                            </div>
                            <div class="col-sm-3">
                                <asp:Button runat="server" ID="CancelButton" OnClick="Cancel" Text="Cancel" CausesValidation="false" CssClass="btn btn-block btn-default" />
                            </div>
                        </div>
                    </div>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </asp:Panel>

</asp:Content>

这是我在后面的代码中的:

protected void bMParentGrid_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                string item = Convert.ToString(DataBinder.Eval(e.Row.DataItem, "Item"));

                string selectedItem = item.Substring(0, item.IndexOf(' ')).Trim();

                GridView bMChildGrid = e.Row.FindControl("bMChildGrid") as GridView;

                // Create Data Table
                DataTable dt = new DataTable();
                dt.Columns.Add("lineNum", typeof(int));
                dt.Columns.Add("Item", typeof(string));
                dt.Columns.Add("Quantity", typeof(int));

                dt.Rows.Add(dt.NewRow());
                bMChildGrid.DataSource = dt;
                bMChildGrid.DataBind();               
            }
        }

我做错了什么?单击父网格行不会显示嵌入其中的子网格。

【问题讨论】:

  • Web 窗体默认更改控件的 ID。您是否检查了 DOMC 以确保 JavaScript 中的 ID 与 DOM 中的 ID 一致?
  • @mason 你的意思是在 Chrome 或 Firefox 中检查?当我单击“+”未捕获的错误:语法错误,无法识别的表达式时,我得到了这个:#imgdivRE002 - Utility Wedge Set 3pc (DG)
  • 是的,我的意思是在浏览器中查看。这就是 DOM 所在的地方。您是否弄清楚哪一行代码会引发该错误?这真的是您希望传递给它的输入吗?
  • 第 193 行并非如此。您正在查看 ASPX。您需要在客户端查看实际呈现的 HTML。 ASPX 不是 HTML,要了解 Web 表单,您需要了解 ASPX 是如何呈现为 HTML 的。
  • 忽略这是网络表单的事实。这几乎是一个 jquery/javascript 问题。在您选择的浏览器中使用“查看源代码”查看发送到浏览器的 html。与它一起工作。 Alos 尝试摆脱对 id 的依赖。改为使用父/子或兄弟关系。

标签: jquery asp.net gridview webforms


【解决方案1】:

嗯,我认为你不应该尝试在 gridview 中嵌套 gridview。

问题在于 GridView 不像列表视图那样支持“行跨度”。

当您展开该 GridView 时,它会尝试放入一列中。

所以网格可能如下所示:

所以我有 + 号来展开/显示嵌套的网格视图,我会得到这个:

(在此示例中展开显示在酒店预订的人)

你会得到这个效果:

现在,您可以使用额外的锤子、锯子、钉子和锤击来扩大网格视图并显示在行下方。

但是,GridView 不能很好地(如果有的话)支持多行行。

但是,listview 可以。因此,您可以很好地保留嵌套(子)gridview,并将其放入 ListView。

因此,列表视图将(应该/可以)看起来非常相似。像这样说:

但是,我可以让嵌套控件(gridview)占据一整行,所以当我在列表视图中展开它时,我得到了:

如您所见,这看起来好多了。而且我不必与系统和布局作斗争 - 它工作得更好。

所以,这是我的 ListView 标记:

    <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >

       <ItemTemplate>
          <tr style="">
            <td><asp:Button ID="cmdView" runat="server" Text="+" CommandName="Select" /></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>

          <tr>
            <td colspan="5">
               <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" 
                 DataKeyNames="ID" CssClass="table table-hover" style="display:none"  >
                    <Columns>
                        <asp:BoundField DataField="Firstname" HeaderText="Firstname" SortExpression="Firstname" />
                        <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
                        <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
                    </Columns>
                </asp:GridView>

            </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>

如果您仔细观察,我们有第一个“tr”(表格行),即重复行。

然后我添加了额外的行 - 给了它一个 col span = 5(所以它占用了一行

所以驱动这个的代码。包括 + 按钮。如果你再次点击 +,那么我会崩溃(隐藏网格视图)。

所以,代码如下所示:

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 strSQL As String

    strSQL = "SELECT * FROM tblHotels ORDER BY HotelName"

    Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST4))

        cmdSQL.Connection.Open()

        ListView1.DataSource = cmdSQL.ExecuteReader
        ListView1.DataBind()

    End Using

End Sub

这样就显示了我们的网格。当然我们有“+”按钮,它只是加载给定行的网格,然后将样式(显示)变为正常。

代码是这样的:

Protected Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged

    Dim gVR As ListViewDataItem = ListView1.Items(ListView1.SelectedIndex)
    Dim gChild As GridView = gVR.FindControl("GridView2")   ' pluck out the grid for this row

    If gChild.Style("display") = "normal" Then
        ' if grid is already display, then hide it, and exit
        gChild.Style("display") = "none"
        Exit Sub
    End If

    gChild.Style("display") = "normal"
    Dim HotelPK As String = ListView1.DataKeys(gVR.DataItemIndex).Item("ID")

    Dim strSQL As String
    strSQL = "SELECT * from People where hotel_id = " & HotelPK

    Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST4))

        cmdSQL.Connection.Open()
        gChild.DataSource = cmdSQL.ExecuteReader
        gChild.DataBind()

    End Using

End Sub

Protected Sub ListView1_SelectedIndexChanging(sender As Object, e As ListViewSelectEventArgs) Handles ListView1.SelectedIndexChanging

End Sub

代码不多,我们得到了很好的向下钻取,甚至可以切换显示、隐藏。

我真的建议您将其移至父级的 ListView。孩子可以保持为 gridView,或者其他任何东西。

请注意 listView 是多么的好 - 您可以在常规控件中拖放 - 您不需要像使用 GridView 那样一遍又一遍地使用模板列。

对于大多数简单的网格 - 或者没有太多自定义的网格,GridView 是相当不错的。

但是,当您有很多自定义控件并且需要很多花哨的东西和更多的灵活性时?然后你必须拿出大手笔,开始使用 ListView。

listview 一开始往往是一个“一点点”的标记,但由于它具有近乎无限的灵活性,那么对于一个复杂而酷炫的网格控件,listView 更能应对挑战,并且布局更加灵活。

ListView 的一大特点是能够为一个数据记录设置多个 ROWS 布局 - 这对于 GridView 来说往往非常困难。 ListView 让您拥有“更多”而不是每个记录的一行详细信息,并拥有有价值的 colspan(甚至还有 rowspan)。

因此,对于一行控件,GridView 很好,但是当您想要更多的数据而不是 JUST 列数据时,ListView 就是这里的门票。

编辑:向该子网格添加行编辑

好的,所以我们有这段代码来加载我们的主列表视图

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 strSQL As String

    strSQL = "SELECT * FROM tblHotels WHERE ID in (select hotel_Id from People)
             ORDER BY HotelName"

    ListView1.DataSource = MyRst(strSQL)
    ListView1.DataBind()

End Sub

我们的 expand + show child gv 代码如下:

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

    Dim cmd As Button = sender

    'Dim gVR As ListViewDataItem = ListView1.Items(ListView1.SelectedIndex)
    Dim gVR As ListViewDataItem = cmd.Parent
    Dim gChild As GridView = gVR.FindControl("GridView2")   ' pluck out the grid for this row

    If gChild.Style("display") = "normal" Then
        ' if grid is already display, then hide it, and exit
        gChild.Style("display") = "none"
        Exit Sub
    End If

    gChild.Style("display") = "normal"
    Dim HotelPK As String = ListView1.DataKeys(gVR.DataItemIndex).Item("ID")

    ' only re-load if never loaded (can't re-load else blow out check boxes

    If gChild.Rows.Count = 0 Then
        Dim strSQL As String
        strSQL = "SELECT * from People where hotel_id = " & HotelPK
        gChild.DataSource = MyRst(strSQL)
        gChild.DataBind()

    End If

End Sub

好的,现在我们需要在子网格中添加一个编辑按钮。

我们可以放入一个平面简asp.net 按钮。但我要加入一个 LinkBut​​ton - 因为它们也可以轻松使用引导图标 - 它们看起来更好。

因此,在我们的子 GV 标记中,我们添加以下内容:

                        <asp:BoundField DataField="City" HeaderText="City"           />
                        <asp:TemplateField HeaderText="Edit" HeaderStyle-Width="140px"
                            ItemStyle-HorizontalAlign="Center" >
                            <ItemTemplate>

                    <asp:LinkButton ID="cmdEdit" runat="server" CssClass="btn btn-default"
                        OnClick="cmdEdit_Click">
                    <span aria-hidden="true" class="glyphicon glyphicon-edit"></span>
                    </asp:LinkButton>

                    <asp:LinkButton ID="cmdDelete" runat="server" CssClass="btn btn-default"
                        style="margin-left:8px" >
                    <span aria-hidden="true" class="glyphicon glyphicon-trash"></span>
                        
                    </asp:LinkButton>

                </ItemTemplate>
            </asp:TemplateField>
           </Columns>
         </asp:GridView>

所以,我只是放入了两个按钮 - 我将它们都填充到一个模板列中。所以,到目前为止,我们现在是这样的:

(我展开一行)

所以,我们有一个编辑按钮和一个删除按钮。

所以,我们需要为弹出窗口构建一个“div”。这只是 div 中的一些简单标记,可让我们编辑行。

这个 div 可以放在 List 视图下方 - 它在 LV 和嵌套 LV 之外 - 它只是平面简 100% 标记。

我有这个:

<div id="myedit" style="float:left;width:20%">
    <div style="text-align:right">
        <p>First Name :<asp:TextBox ID="txtFirstname" runat="server" Width="150"></asp:TextBox> </p>
        <p>Last Name :<asp:TextBox ID="txtLastname" runat="server" Width="150"></asp:TextBox> </p>
        <p>City  :<asp:TextBox ID="txtCity" runat="server" Width="150"></asp:TextBox> </p>
        <p>Active :<asp:CheckBox ID="Active" runat="server" Width="150"></asp:CheckBox> </p>
        <br />
    </div>
    <div style="text-align:right">
        Notes :
        <asp:TextBox ID="txtNotes" runat="server" Width="240px" TextMode="MultiLine" Height="71px"></asp:TextBox> <br />
        <br />
        <asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" Width="90px"
             />
        <asp:Button ID="cmdCancel" runat="server" Text="Cancel" cssclass="btn" Width="90px"
          OnClientClick="$('#myedit').dialog('close');return false;" style="margin-left:8px"  />
    </div>
</div>

当在页面上渲染时,它看起来像这样:

那么,第一个挑战是什么?我们需要一个对话系统。有船载。但是,最常见的两个是 bootstrap 和 jQuery.UI。

我发现引导对话框看起来非常好。但与它们一起工作很痛苦。

所以,我们要在这里硬着头皮。毫无疑问,您的网站中正在使用并拥有 jQuery - (现在不都是吗???)。

因此,您必须添加并采用 jQuery.UI。它是一个小型 js 库,但我强烈建议您采用它 - 它可以正常工作,并且允许您现在引入弹出对话框。这真的很好 - 我们甚至使用删除按钮(确认对话框)。

所以,为单行编辑布置 div。

然后我们用 style="display:none" 隐藏 div。

我们有一个客户端脚本例程——这个例程的唯一工作就是弹出那个对话框。

所以,我们现在有了这个:

 <div id="myedit" style="float:left;width:20%;display:none">
    <div style="text-align:right">
        <p>First Name :<asp:TextBox ID="txtFirstname" runat="server" Width="150"></asp:TextBox> </p>
        <p>Last Name :<asp:TextBox ID="txtLastname" runat="server" Width="150"></asp:TextBox> </p>
        <p>City  :<asp:TextBox ID="txtCity" runat="server" Width="150"></asp:TextBox> </p>
        <p>Active :<asp:CheckBox ID="Active" runat="server" Width="150"></asp:CheckBox> </p>
        <br />
    </div>
    <div style="text-align:right">
        Notes :
        <asp:TextBox ID="txtNotes" runat="server" Width="240px" TextMode="MultiLine" Height="71px"></asp:TextBox> <br />
        <br />
        <asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" Width="90px"
             />
        <asp:Button ID="cmdCancel" runat="server" Text="Cancel" cssclass="btn" Width="90px"
          OnClientClick="$('#myedit').dialog('close');return false;" style="margin-left:8px"  />
    </div>
</div>
        <script>
            function MyEdit() {
                // pop the div dialog to edit
                var myDialog = $("#myedit");
                myDialog.dialog({
                    modal: true,
                    width: "280px",
                    resizable: false,
                    appendTo: "form",
                    autoOpen: false
                });
                myDialog.dialog('open');
            }
        </script>

因此,我们将 jQuery.ui 添加到此页面。我的设置如下所示:

<head runat="server">
<title></title>

<script src="Scripts/jquery-1.12.4.js"></script>
<script src="Scripts/bootstrap.js"></script>
<link href="Content/bootstrap.css" rel="stylesheet" />

<link href="Content/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="Scripts/jquery-ui-1.12.1.js"></script>

现在,我们可以采用一堆花哨的裤子客户端代码。但是为了保持简单?

从现在开始,其他一切都是 CLEAN EASY 纯服务器端代码。我想随着时间的推移,您可以 ajax 对话框 - 引入一些 Web 方法调用 - 但这可能需要相当多的额外工作 - 我们不需要这样做。

好的,第一部分:

我们需要在 GV 的“编辑”按钮中连接事件点击按钮。 我们不能只是简单地双击按钮来创建点击事件。 (因为它嵌套在 lv 和 gv 中)。因此,从标记,对于编辑按钮,我们转到标记,并在点击时输入,注意非常非常酷的是我们提供了如何在点击事件后面创建简单的代码。

例如:

所以,选择创建新事件 - 它似乎没有发生任何事情,但翻转到代码后面,我们的代码在 click stub 后面。

在这个编辑按钮中?

我们得到 gv 行,从数据库中提取数据。将值推入我们很酷的编辑 div,然后弹出对话框。

代码现在是这样的:

Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)
    ' nested grid eit button.

    Dim cmdEdit As LinkButton = sender
    Dim gRow As GridViewRow = cmdEdit.NamingContainer
    Dim GV As GridView = gRow.NamingContainer
    Dim PkID As Integer = GV.DataKeys(gRow.RowIndex).Item("ID")

    Dim strSQL As String = "SELECT * from People WHERE ID = " & PkID

    Dim rstData As DataTable = MyRst(strSQL)

    ' load up our edit div
    With rstData.Rows(0)
        txtFirstname.Text = .Item("FirstName").ToString
        txtLastname.Text = .Item("LastName").ToString
        txtCity.Text = .Item("City").ToString
        If IsDBNull(.Item("Active")) Then
            Active.Checked = False
        Else
            Active.Checked = .Item("Active")
        End If
        txtNotes.Text = .Item("Notes").ToString
    End With

    Session("RowPK") = PkID
    ' save current list view row
    Dim LV As ListViewItem = GV.NamingContainer
    Session("LvRow") = LV.DataItemIndex

    ' now pop the dialog
    Page.ClientScript.RegisterStartupScript(Me.GetType(),
                                            "My pop", "MyEdit()", True)

End Sub

现在不是很多代码 - 但充满了巨大的提示和技巧!!!

注意我如何抓取 gv 行。请注意我如何获得 PK id。这些都是非常巧妙的技巧。

所以我们拉出一个数据行,推入 div,然后我们要做的最后一件事是设置页面以运行我们很酷的小 div 弹出对话框。

现在的结果是这样的:

现在,对于取消按钮(什么都不做),我们不需要任何实际代码 - 我们只需关闭对话框。

所以那个按钮是这样的:

 <asp:Button ID="cmdCancel" runat="server" Text="Cancel" cssclass="btn" Width="90px"
 OnClientClick="$('#myedit').dialog('close');return false;" style="margin-left:8px"  />

但是,我们的保存按钮?我们必须把文本框拿回数据库。

所以,保存按钮不仅要保存数据,而且当我们关闭对话框时,我们需要重新绘制(重新加载)gv - 实际上这会花费我们一些额外的代码 - 但我们需要它。

So, the save button will:
Pull text boxes back into table. 
Save send table back to database
re-load re-fresh gv

代码是这样的:

 Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click

    Dim strSQL = "SELECT * FROM People where ID = " & Session("RowPK")
    Dim rstData As DataTable = MyRst(strSQL)

    With rstData.Rows(0)
        .Item("FirstName") = txtFirstname.Text
        .Item("LastName") = txtLastname.Text
        .Item("City") = txtCity.Text
        .Item("Active") = Active.Checked
        txtNotes.Text = .Item("Notes").ToString
    End With

    ' save to database
    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            Dim da As New SqlDataAdapter(cmdSQL)
            Dim daU As New SqlCommandBuilder(da)
            conn.Open()
            da.Update(rstData)
        End Using
    End Using

    ' since save button does a post back? 
    ' then dialog will collpase - no need to close.

    ' we now need to re-load (refrsh) the GV to display
    ' changes
    Dim LVitem As ListViewItem = ListView1.Items(Session("LvRow"))
    ' get Gird from this row
    Dim GV As GridView = LVitem.FindControl("GridView2")

    Dim HOtelPk As Integer = rstData.Rows(0).Item("Hotel_id")
    strSQL = "SELECT * from People where hotel_id = " & HOtelPk
    Dim rstGV As DataTable = MyRst(strSQL)
    GV.DataSource = rstGV
    GV.DataBind()

End Sub

现在不会太长 - 但会突破代码屏幕的限制!!!

再次注意获取 GV 行的巧妙方法 - 我们在编辑时保存到会话中单击 LV 行 - 我们可以再次在页面中使用隐藏字段 - 因此您可以使用多种方法 - 取决于您当前的需求.

好的。就是这样!!!

现在,删除按钮?我们有这个:

再次,公平地说 - 必须重新绘制 Gv 成本代码。

但是,还不错:

Protected Sub cmdDelete_Click(sender As Object, e As EventArgs)
    ' delete this gv row

    Dim cmdDel As LinkButton = sender
    Dim gRow As GridViewRow = cmdDel.NamingContainer
    Dim GV As GridView = gRow.NamingContainer
    Dim PkID As Integer = GV.DataKeys(gRow.RowIndex).Item("ID")

    Dim LVrow As ListViewItem = GV.NamingContainer
    Dim ParentPK As Integer = ListView1.DataKeys(LVrow.DataItemIndex).Item("ID")

    Dim strSQL As String = "DELETE FROM People WHERE ID = " & PkID

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            cmdSQL.ExecuteNonQuery()
        End Using
    End Using

    ' refresh grid

    Dim rstData As DataTable =
        MyRst("SELECT * FROM People WHERE Hotel_id = " & ParentPK)
    GV.DataSource = rstData
    GV.DataBind()

End Sub

既然我们真的有那么酷的对话系统?然后让我们弹出一个很酷的确认对话框。 (我们不必为此碰运气上面的删除代码。

Edit2:网格底部的添加按钮

好的,我们有一个编辑,但现在让我们设置一个添加按钮。

我们必须将此按钮放在网格下方,然后我们隐藏/显示网格。

所以,我们修改 GV - 我们现在要隐藏/显示 ROW!!!

所以,我们有这个:

          <td id="mygridview" colspan="5" runat="server" style="display:none">

               <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" 
                 DataKeyNames="ID" CssClass="table table-hover" style="margin-left:3%;width:97%"  >
                    <Columns>
                        <asp:BoundField DataField="Firstname" HeaderText="Firstname" />
                        <asp:BoundField DataField="LastName" HeaderText="LastName"   />
                        <asp:BoundField DataField="City" HeaderText="City"           />
                        <asp:TemplateField HeaderText="Edit" HeaderStyle-Width="140px"
                            ItemStyle-HorizontalAlign="Center" >
                            <ItemTemplate>

                    <asp:LinkButton ID="cmdEdit" runat="server" CssClass="btn btn-default"
                        OnClick="cmdEdit_Click">
                    <span aria-hidden="true" class="glyphicon glyphicon-edit"></span>
                    </asp:LinkButton>

                    <asp:LinkButton ID="cmdDelete" runat="server" CssClass="btn btn-default"
                        OnClientClick="return delconfirm(this);"
                        OnClick="cmdDelete_Click"

                        style="margin-left:8px" >
                    <span aria-hidden="true" class="glyphicon glyphicon-trash"></span>
                        
                    </asp:LinkButton>

                </ItemTemplate>
            </asp:TemplateField>
           </Columns>
         </asp:GridView>
        
         <asp:Button ID="cmdAddRow" runat="server" Text="+"
             style="float:right;margin-right:5px" Width="40px"
             OnClick="cmdAddRow_Click"
             
             />
            </td>

所以,我们必须更新我们的展开按钮代码 - 抱歉 - 但我们有更多 GV 来显示隐藏。这样代码就变成了这样:

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

    Dim cmd As Button = sender

    'Dim gVR As ListViewDataItem = ListView1.Items(ListView1.SelectedIndex)
    Dim gVR As ListViewDataItem = cmd.Parent
    Dim gChild As GridView = gVR.FindControl("GridView2")   ' pluck out the grid for this row
    Dim MyDiv As HtmlTableCell = gVR.FindControl("mygridview")

    If MyDiv.Style("display") = "normal" Then
        ' if grid is already display, then hide it, and exit
        MyDiv.Style("display") = "none"
        Exit Sub
    End If

    MyDiv.Style("display") = "normal"

    Dim HotelPK As String = ListView1.DataKeys(gVR.DataItemIndex).Item("ID")

    ' only re-load if never loaded (can't re-load else blow out check boxes

    If gChild.Rows.Count = 0 Then
        Dim strSQL As String
        strSQL = "SELECT * from People where hotel_id = " & HotelPK
        gChild.DataSource = MyRst(strSQL)
        gChild.DataBind()

    End If

End Sub

变化不大 - 但我们隐藏/显示该行,因为我们现在有 GV 和按钮。

现在看起来像这样:

我们的添加按钮点击代码现在是这样的:

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

    Dim cmdAdd As Button = sender
    Dim LVrow As ListViewItem = cmdAdd.NamingContainer

    ' get PK of parent row
    Dim ParentPK As Integer = ListView1.DataKeys(LVrow.DataItemIndex).Item("ID")

    ' clear edit div
    txtFirstname.Text = ""
    txtLastname.Text = ""
    txtCity.Text = "Edmonton"
    Active.Checked = True
    txtNotes.Text = ""

    Session("LvRow") = LVrow.DataItemIndex
    Session("RowPK") = 0

    ' now pop the Edit dialog
    Page.ClientScript.RegisterStartupScript(Me.GetType(),
                                            "My pop", "MyEdit()", True)

End Sub

现在因为我们有编辑和添加? 好吧,那么我们的保存例程需要稍作改动。

(因此它可以同时处理编辑/保存和现在的新记录)

所以,我们稍微调整一下:

Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click

    ' if new row - add it!!!
    Dim RowPK As Integer = Session("RowPK")

    Dim strSQL = "SELECT * FROM People where ID = " & Session("RowPK")
    Dim rstData As DataTable = MyRst(strSQL)

    Dim LVitem As ListViewItem = ListView1.Items(Session("LvRow"))
    ' get Gird from this row
    Dim GV As GridView = LVitem.FindControl("GridView2")

    Dim HOtelPk As Integer = ListView1.DataKeys(LVitem.DataItemIndex).Item("ID")

    Dim OneRow As DataRow

    If rstData.Rows.Count = 0 Then
        OneRow = rstData.NewRow
        OneRow("Hotel_ID") = HOtelPk
        rstData.Rows.Add(OneRow)
    Else
        OneRow = rstData.Rows(0)
    End If

    OneRow("FirstName") = txtFirstname.Text
    OneRow("LastName") = txtLastname.Text
    OneRow("City") = txtCity.Text
    OneRow("Active") = Active.Checked
    OneRow("Notes") = txtNotes.Text

    ' save to database
    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            Dim da As New SqlDataAdapter(cmdSQL)
            Dim daU As New SqlCommandBuilder(da)
            conn.Open()
            da.Update(rstData)
        End Using
    End Using

    ' since save button does a post back? 
    ' then dialog will collpase - no need to close.

    ' we now need to re-load (refrsh) the GV to display
    ' changes

    strSQL = "SELECT * from People where hotel_id = " & HOtelPk
    Dim rstGV As DataTable = MyRst(strSQL)
    GV.DataSource = rstGV
    GV.DataBind()

End Sub

几乎一样!!! - 但是我们设置了父 PK(以及此行的 FK),然后我们创建一个新行,或者获取现有行。

最后但并非最不重要?我有几个地方需要提取数据。我的键盘已经磨损了。所以我有这个帮助程序来返回一个数据表。

这是一个方便的例程。请记住,仅对来自数据键的 PK 值使用字符串连接 - 切勿将其用于来自网页的用户输入。

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

【讨论】:

  • 我决定走你的路。更干净,AutoCompleteExtender 没有隐藏的 div 也能很好地工作。
  • 很高兴这个作品。我的意思是,我整个很酷的网格展开按钮 - Ondinex 更改事件有哪些 12 行代码?你会得到这个很棒的用户界面。这里有一个教训:如果您编写了太多代码并与 UI 作斗争?然后尝试另一条路。上面加载、显示和扩展的代码不仅是简单的代码——而且标记也非常有限,而不是大量混乱的标记页面。 LESS 代码和 LESS 标记是这里更好的选择。
  • 我使用了您建议的这种方法。现在我需要在 girdview 行上创建一个单击事件,以便用户能够添加更多行。我该怎么做?
  • 那么,这样的添加行按钮不会放在网格下方吗?换句话说,您可以轻松地将一个按钮放到 GV 上,然后说当您单击它时查看该行中的数据(可能是一个很酷的弹出窗口)。但是,我认为我们不希望每行出现一个重复的“添加”按钮来添加一行? (我的意思是,有 5 行,我们将有 5 个添加按钮?不应该只是 GV 正下方的一个简单按钮更有意义 - 说“添加新”。但要回答这个问题,是的,GV 内部的一个简单按钮(或在 GV 下方更好)很简单,只需几行代码。
  • 但是,我们是否会弹出一个对话框以输入新的 GV 行,或者您是否要打开现有的 GV 以允许编辑?如果是,那么我们需要一个保存按钮,然后在该 GV 下方添加一个添加行按钮,对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
相关资源
最近更新 更多