65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 AJAX 的分层 GridView 控件

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.69/5 (14投票s)

2010年2月20日

CPOL

3分钟阅读

viewsIcon

69012

downloadIcon

3527

解释如何在 ASP.NET 中使用 AJAX 创建分层 GridView 控件

引言

HierachicalGridViewImage_small.gif

本文讲解了如何创建一个分层 GridView 控件。我在一个项目中实现了这个 GridView,大约两年前。当时我就想发布它,但由于时间不够而未能如愿。现在,在紧张的时间安排下,我终于发布了它。您可以使用这个 GridView 来以父子模型显示数据。在这个例子中,我只使用了一个子 GridView。使用这段代码,您可以通过在子 GridView 下创建更多的子 GridView 来将子 GridView 转换为父 GridView。

背景

该项目使用了两个 GridView 和两个 ObjectDataSourceGridView 的 ID 分别是 grdOrdersgrdOrderDetails。SQL Express 被用作后端服务器,NorthWind 是该模块的数据库。在本例中,grdOrders 被称为父 GridView,grdOrderDetails 被称为子 GridView,它位于 grdOrders 内部。默认情况下,子 GridView 的 Visible 属性为 false。父 GridView 将显示订单。当用户点击父 GridView 的某一行时,子 GridView 将可见并显示订单详情数据。

Using the Code

这是用于从业务逻辑层提取数据的 ObjectDataSource 声明:

<asp:ObjectDataSource ID="objDataSourceID" 
                        runat="server" 
                        SelectMethod="GetOrders" 
                        EnablePaging="true" 
                        TypeName="clsGeneralFunctions" 
                        StartRowIndexParameterName="StartRowIndex" 
                        MaximumRowsParameterName="MaximumRows" 
                        SelectCountMethod="GetOrdersCount">
</asp:ObjectDataSource>

上面的 ObjectDataSource 用于从业务逻辑层为父 DataGrid 提取数据。StartRowIndexParameterNameMaximumRowsParameterName 属性用于仅提取当前页面需要显示的数据记录。SelectCountMethod 属性用于拉取实际查询将返回的总记录数,该数量用于根据 PageSize 属性在 GridView 上显示总页数。当用户在 GridView 中选择某个页码时,ObjectDataSource 将执行分配给 SelectMethod 属性的 GetOrders 方法。如果 EnablePaging 属性设置为 False,那么 StartRowIndexParameterNameMaximumRowsParameterName 属性就没有意义了,也就是说,我们无法仅拉取当前页面需要显示的数据记录。

<asp:ObjectDataSource   ID="objOrderDetails" 
                           runat="server" 
                           SelectMethod="GetOrdersDetailsList" 
                           EnablePaging="true" 
                           TypeName="clsGeneralFunctions" 
                           SelectCountMethod="GetOrdersDetailsCount">
   <SelectParameters>
   <asp:Parameter Direction="Input" 
        Name="StartRowIndex" type="Int32" />
   <asp:Parameter Direction="Input" 
        Name="MaximumRows" type="Int32" />
   <asp:Parameter Direction="Input" 
        Name="OrderId" 
        DefaultValue="0" type="Int32" />
   </SelectParameters>
</asp:ObjectDataSource>

上面的 ObjectDataSource 用于从业务逻辑层为子 DataGrid 提取数据,数据基于来自父 GridView 的 Order ID。当用户点击父 GridView 的某个订单时,子 GridView 将显示所选订单的订单详情。上面的 ObjectDataSource 有一个额外的输入参数,名为 OrderId,用于将 Order ID 传递给分配给 SelectCountMethodSelectMethod 属性的方法。

protected void grdOrders_RowDataBound(object sender, GridViewRowEventArgs e)
{{
    ImageButton imgBtn;

    if (e.Row.RowType == DataControlRowType.DataRow)
    {

        imgBtn = (ImageButton)(e.Row.FindControl("ImgBtn"));
        imgBtn.CommandArgument = e.Row.RowIndex.ToString();

        if (e.Row.Cells[0].Text == Session["OrderId"])
        {
            PlaceHolder objPH;
            objPH = (PlaceHolder)(e.Row.FindControl("objPHOrderDetails"));
            if (objPH != null)
                objPH.Visible = true;

            if (imgBtn.ImageUrl == "Include/images/gridplus.gif")
                imgBtn.ImageUrl = @"Include/images/gridminus.gif";
            else
                imgBtn.ImageUrl = @"Include/images/gridplus.gif";
        }
    }
}

GridView 中的行被创建时,会触发上面的 RowDataBound 事件。该事件用于将 GridView 的行号设置为 ImageButtonCommandArgument 属性。当用户点击父 GridView 上的 ImageButton 时,该属性将在父 GridView 的 RowCommand 事件中使用。

protected void grdOrders_RowCommand(object sender, GridViewCommandEventArgs e)
{
    if (e.CommandName == "Expand")
    {
        ImageButton imgbtn;
        GridView gv = (GridView)(sender);
        Int32 rowIndex = Convert.ToInt32(e.CommandArgument.ToString());
        PlaceHolder objPH = 
          (PlaceHolder)(gv.Rows[rowIndex].FindControl("objPHOrderDetails"));
        ObjectDataSource objDS = 
          (ObjectDataSource)(gv.Rows[rowIndex].FindControl("objOrderDetails"));
        GridView objChildGrid = 
          (GridView)(gv.Rows[rowIndex].FindControl("grdOrderDetails"));
        imgbtn = (ImageButton)(gv.Rows[rowIndex].FindControl("ImgBtn"));

        objDS.SelectParameters["OrderId"].DefaultValue = 
                    gv.DataKeys[rowIndex][0].ToString();
        Session["OrderId"] = gv.DataKeys[rowIndex][0].ToString();

        if (imgbtn.ImageUrl == "Include/images/gridplus.gif")
        {
            imgbtn.ImageUrl = @"Include/images/gridminus.gif";
            if (objChildGrid != null)
            {
                if (objPH != null)
                    objPH.Visible = true;
                objChildGrid.Visible = true;
            }
        }
        else
        {
            if (objChildGrid != null)
            {
                imgbtn.ImageUrl = @"Include/images/gridplus.gif";
                if (objPH != null)
                    objPH.Visible = false;
                objChildGrid.Visible = false;
            }
        }
    }
}

if 条件 (e.CommandName == "Expand") 用于验证用户是否点击了 ImageButton。值 "Expand" 已被设置为 ImageButtonCommandName 属性。当用户点击 ImageButton 时,我们将创建父 GridView 控件中所有控件的对象,将选定的行(即 Order ID)传递给子数据源,该子数据源将拉取所选订单的所有订单详情记录。一旦数据被填充到子 GridView 中,我们就应该将加号(+)符号的图像按钮更改为减号(-)符号,并将子 GridView 和 PlaceHolderVisible 属性设置为 true。下次用户点击同一行时,减号符号应更改为加号符号,并将子 GridView 和 PlaceHolderVisible 属性设置为 false,这由 else 语句实现。

关注点

由于我们对 ASP.NET 比较陌生,因此在这个项目中学习了许多新控件。

© . All rights reserved.