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

ASP.NET 扩展 Grid 控件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.60/5 (8投票s)

2010年1月13日

CPOL

5分钟阅读

viewsIcon

37026

downloadIcon

965

EnhanceGrid:支持自定义分页、每页记录数和搜索功能。

引言

在本文中,我将讨论我的 EnhanceGrid,它具有以下功能:

  1. 自定义分页,仅提取所需的记录数
  2. 列标题中的图标,用于显示排序方向
  3. 分页器中的下拉列表,用于调整每页的记录数
  4. 扩展 Grid 的属性
  5. 如何使用自定义 Grid 控件

自定义分页,仅提取所需的记录数

以下是我用于为自定义 Grid 提供自定义分页功能的存储过程。注释解释了字段并提供了有关存储过程的详细信息。

CREATE PROCEDURE [dbo].[GetRequestedRecordByPage] 
 @FromList nvarchar(200)              -- Table Name  
,@SortingCol nvarchar(200)         -- Sorting column Name
,@SelectList nvarchar(200) = '*'         -- Select columns list
,@WhereClause nvarchar(200) = ''        -- Where clause i.e condition
,@PageNum int = 1                           -- Requested page number
,@PageSize int = 5                 -- No of record in page
,@TotalNoOfRecord int output         -- Total no of selected records
AS 
Begin
  SET NOCOUNT ON 
  DECLARE @Query nvarchar(max)         -- query going to be execute
 
  IF rtrim(ltrim(@WhereClause)) <> '' 
  BEGIN
      SET @Query ='SELECT   @TotalNoOfRecord = COUNT(*) 
                      FROM     ' + @FromList + ' 
        WHERE    ' + @WhereClause 
  END
  ELSE 
  BEGIN 
      SET @Query ='SELECT   @TotalNoOfRecord = COUNT(*) 
                      FROM     ' + @FromList 
  END

    /* Count no. of record */
       EXEC sp_executeSQL 
        @Query, 
        @params = N'@TotalNoOfRecord INT OUTPUT', 
         = @TotalNoOfRecord OUTPUT 

DECLARE @lbound int, @ubound int 




/* Calculating upper and lower bound */
        SET @lbound = ((@PageNum - 1) * @PageSize) 
        SET @ubound = @lbound + @PageSize + 1 


/* Get list of record(s) */
        SELECT @Query =  ''
        SELECT @Query =  'SELECT  * 
                          FROM    ( 
SELECT  ROW_NUMBER() OVER(ORDER BY ' + @SortingCol  + ') AS rownumber,' +@SelectList  +   
                                        ' FROM    ' + @FromList 
        
        IF rtrim(ltrim(@WhereClause)) <> '' 
        BEGIN
            SELECT @Query = @Query + ' WHERE   ' + @WhereClause 
        END

            SELECT @Query = @Query + '     ) AS tbl 
WHERE rownumber > ' + CONVERT(varchar(9), @lbound) + 
      ' AND rownumber < ' + CONVERT(varchar(9), @ubound) 
 
       EXEC (@Query)                 
End

正如您所看到的,上述过程是通用的,因此可以用于任何地方。因此,我已将其包含在我的 EnhanceGrid 中,因为它适用于用 ASP.NET 开发的任何项目。

列标题中的图标,用于显示排序方向

为了在标题文本中显示排序图标,我覆盖了 .NET Framework 中标准 Grid 控件的以下事件。

  • OnRowCreated:在创建行时会触发此事件。这里,如果 RowTypeHeader,则通过获取被单击项的索引来添加排序图标,然后调用 SortingIcon 方法将图标添加到标题行。
  • protected override void OnRowCreated(GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.Header)
        {
            /* Get sorting column index */
            int index = GetSortColumnIndex();
            if (index != -1)
            {
                sortingIcon(index, e.Row);
            }
        }
    }
  • OnSorting:当用户单击标题列以对 Grid 控件的记录进行排序时,将调用此事件。从下面的代码可以看出,它将列排序表达式存储在 lblSortExp 中,将排序方向存储在 lblSortDirection 中,并反转当前存储的值。
  • protected override void OnSorting(GridViewSortEventArgs e)
    {
        try
        {
            lblSortExp = e.SortExpression;
    
            switch (lblSortDirection)
            {
                case "asc":
                {
                    lblSortDirection = "desc";
                    break;
                }
                case "desc":
                case "":
                case null:
                {
                    lblSortDirection = "asc";
                    break;
                }
            }
            BindGrid();
        }
        catch (Exception ex) { }
    }
  • sortingIcon:此函数用于在列标题中添加排序图标。在此函数中,我创建了一个 Label,该 Label 动态添加到被单击标题列的标题文本中。
  • private void sortingIcon(int index, GridViewRow row)
    {
        System.Web.UI.WebControls.Label lblSorting = 
                      new System.Web.UI.WebControls.Label();
        if (lblSortDirection == "desc")
        {
            lblSorting.Text = "<span style=\"font-family:" + 
                              "Marlett; font-weight:bold\">6</span>";
        }
        else
        {
            lblSorting.Text = "<span style=\"font-family:Marlett;" + 
                              " font-weight:bold\">5</span>";
        }
        row.Cells[index].Controls.Add(lblSorting);
    }
  • GetSortColumnIndex:此函数用于获取用户单击以进行排序的列的索引。在此函数中,我将单击的列的排序表达式与每一列进行比较,并获取被单击列的索引。这是必需的,因为我不知道被单击列的索引。
  • private int GetSortColumnIndex()
    {
        foreach (DataControlField field in this.Columns)
        {
            if (field.SortExpression.ToString() == lblSortExp)
            {
                return this.Columns.IndexOf(field);
            }
        }
        return -1;
    }

分页器中的下拉列表,用于调整每页的记录数

对于每页记录数,我覆盖了与显示排序图标时相同的函数,但这里的条件已更改。正如您下面看到的,我检查了分页器类型的行。在下面的代码中,我创建了一个下拉列表控件,其中包含每页的记录数以及附加的选定更改事件。

protected override void OnRowCreated(GridViewRowEventArgs e)
{
    try
    {
        if (e.Row.RowType == DataControlRowType.Pager)
        {
            DropDownList ddl ddlNoPages = new DropDownList();
            //adds variants of pager size
            ddlNoPages.Items.Add("10");
            ddlNoPages.Items.Add("50");
            ddlNoPages.Items.Add("100");
            ddlNoPages.AutoPostBack = true;
            //selects item due to the GridView current page size
            ListItem li = ddlNoPages.Items.FindByText(this.PageSize.ToString());
                    
            if (li != null)
                ddlNoPages.SelectedIndex = ddlNoPages.Items.IndexOf(li);
           
            ddlNoPages.SelectedIndexChanged += 
              new EventHandler(ddlNoPages _SelectedIndexChanged);
          
            //adds dropdownlist in the additional cell to the pager table
            Table pagerTable = e.Row.Cells[0].Controls[0] as Table;
            TableCell cell = new TableCell();
            cell.Style["padding-left"] = "50px";
            cell.Style["text-align"] = "right";
            cell.Controls.Add(new LiteralControl("Page Size:"));

            cell.Controls.Add(ddlNoPages);
            //e.Row.Cells[0].Controls.Add(cell);
            pagerTable.Rows[0].Cells.Add(cell);
       }
   }
   catch (Exception ex)
   {
   }
}

当组合框索引更改时,将触发以下事件。代码非常简单易懂,因此我认为无需详细解释。

void ddlNoPages_SelectedIndexChanged(object sender, EventArgs e)
{
    if (PageSize > int.Parse(((DropDownList)sender).SelectedValue))
        IsPagesizeChanged = true;
    else
        IsPagesizeChanged = false;
    PageIndex = 0;
    //changes page size
    PageSize = int.Parse(((DropDownList)sender).SelectedValue);
    //binds data source
    BindGrid();
}

注意:此方法仍存在一些我正在处理的错误,我将提供完整的解决方案。

在完成上述操作后,您需要为自定义分页存储过程覆盖 Grid 的以下方法才能正常工作。在此方法中,您必须为分页数据源属性设置值。

protected override void InitializePager(GridViewRow row, 
          int columnSpan, PagedDataSource pagedDataSource)
{
   try
   {
     #region code for standard paging
     //To set custome paging
     pagedDataSource.AllowCustomPaging = true;
     //To set total no of records retived 
     pagedDataSource.VirtualCount = Convert.ToInt32(lbltotal);
     //To set current page index
     pagedDataSource.CurrentPageIndex = lblpageIndex;
     #endregion code for standard paging
               
     base.InitializePager(row, columnSpan, pagedDataSource);
    }
    catch (Exception ex) { }
}

您也可以根据客户要求覆盖上述方法,以提供不同类型的自定义分页。

扩展 Grid 的属性

请注意,大多数属性的值都来自 ViewState,并在 ViewState 中设置。正是通过使用 ViewState 机制,Grid 在回发事件期间才能保留属性值。

这里需要注意的另一件事是,控件 ID 附加到每个 ViewState 属性,因为如果您将相同的 Grid 控件拖放到一个页面上两次或更多次,它将正常工作而不会干扰其他 Grid 操作。

  • lbltotal:Grid 的此属性用于存储存储过程检索的总记录数;它用于相应地调整分页。
  • public int lbltotal
    {
        get
        {
            if (null != ViewState["lbltotal" + ControlID])
                     return (int)ViewState["lbltotal" + ControlID];
            else
                     return 0;
        }
        set
        {
              ViewState["lbltotal" + ControlID] = value;
        }
    }
  • lblpageIndex:存储当前页索引。
  • public int lblpageIndex
    
    {
       get
       {
            if (null != ViewState["lblpageIndex" + ControlID])
                    return (int)ViewState["lblpageIndex" + ControlID];
            else
                     return 0;
       }
       set
       {
              ViewState["lblpageIndex" + ControlID] = value;
       }
    }
  • lblSortDirection:存储列的排序方向。
  • public string lblSortDirection
    {
      get
      {
         if (null != ViewState["lblSortDirection" + ControlID])
            return (string)ViewState["lblSortDirection" + ControlID];
         else
            return string.Empty;
      }
      set
      {
         ViewState["lblSortDirection" + ControlID] = value;
      }
    }
  • lblSortExp:存储排序表达式,即列排序表达式。
  • public string lblSortExp
    {
        get
        {
            if (null != ViewState["lblSortExp" + ControlID])
                return (string)ViewState["lblSortExp" + ControlID];
            else
                return string.Empty;
        }
        set
        {
            ViewState["lblSortExp" + ControlID] = value;
        }
    }
  • FromClause:存储传递给存储过程以检索记录的查询的 From 子句。
  • public string FromClause
    {
        get
        {
           if (null != ViewState["fromClause" + ControlID])
             return (string)ViewState["fromClause" + ControlID];
           else
              return string.Empty; 
        }
        set
        {
             ViewState["fromClause" + ControlID] = value;
        }
    }
  • WhereClause:存储作为查询的 WHERE 条件传递给存储过程的查询的 Where 子句。
  • public string WhereClause
    {
        get
        {
            if (null != ViewState["whereClause" + ControlID])
                return (string)ViewState["whereClause" + ControlID];
             else
                 return string.Empty;
         }
         set
         {
             ViewState["whereClause" + ControlID] = value;
         }
    }
  • SelectList:存储将传递给存储过程的 SELECT 列表列名。
  • public string SelectList
    {
       get
       {
           if (null != ViewState["selectList" + ControlID])
               return (string)ViewState["selectList" + ControlID];
           else
               return string.Empty;
       }
       set
       {
           ViewState["selectList" + ControlID] = value;
       }
    }
  • ControlID:存储控件的 ID。
  • private string _controlId;
    
    public string ControlID
    {
       get { return _controlId; }
       set { _controlId = value; }
    }
  • DefaultSortExp:存储 Grid 在第一次排序事件发生之前用于排序目的的默认排序表达式。
  • private string _DefaultSortExp;
    public string DefaultSortExp
    {
         set{ _DefaultSortExp = value;}
         get{ return _DefaultSortExp;}
    }

其他重要事项

以下属性允许在使用 Grid 控件时附加您自己的事件。

public event GridViewRowEventHandler onRowCreate
{
    add
    {
        base.RowCreated += value;
    }
    remove
    {
        base.RowCreated -= value;
    }
}

public event GridViewSortEventHandler onSort
{

    add
    {
         base.Sorting += value;
    }
    remove
    {
         base.Sorting -= value;
    }
}

如何使用自定义 Grid 控件

以下是注册 Grid 控件的页面代码。

<%@ Register TagPrefix="cc"  Namespace="AppEngine.ComponentControls" Assembly="__code" %>

这是在使用 Grid 控件的 ASPX 页面上的代码。

<cc:MyGridView  runat="server" ID="grdEmployee" 
      AutoGenerateColumns="False" AllowPaging="true"
      AllowSorting="true" DefaultSortExp="FIRSTNAME"
      EnableSortingAndPagingCallbacks = "false">
  <Columns>
    <asp:BoundField DataField="FIRSTNAME" 
        HeaderText="FIRSTNAME" SortExpression="FIRSTNAME" />
    <asp:BoundField DataField="LASTNAME" 
        HeaderText="LASTNAME" SortExpression="LASTNAME" />
    <asp:BoundField DataField="LOGINNAME" 
        HeaderText="LOGINNAME" SortExpression="LOGINNAME" />
    <asp:BoundField DataField="EMAIL" 
        HeaderText="EMAIL" SortExpression="EMAIL" />
  </Columns>
  <PagerSettings Mode="NumericFirstLast" Position ="TopAndBottom"
             PageButtonCount="5"  />
  <PagerStyle BackColor="Pink" />
</cc:MyGridView>

以下代码是您 aspx.cs 文件的一部分。从下面的代码可以看出,我指定了 SelectList(这是一个列列表);FromClause 包含表名,这里是 Employee;WhereClause 包含筛选条件。

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        grdEmployee.SelectList = "[FIRSTNAME],[LASTNAME],[LOGINNAME],[EMAIL]";
        grdEmployee.FromClause = "[EMPLOYEE]";
        grdEmployee.WhereClause = string.Empty;
        //grdEmployee.WhereClause = "[FIRSTNAME] like '%a'";
        grdEmployee.BindGrid();
    }
}

Grid 搜索

以下是 EnhanceGrid 控件中搜索数据的示例。

为了搜索,我在放置 Grid 控件的页面上添加了以下控件,这有助于搜索记录。

  • ddlColumn:包含将由 EnhanceGrid 控件显示的列名。这里需要注意的是,列表项的值字段是数据库表列的名称。
  • txtValue:控件允许用户输入要搜索特定列的值。
  • <div style="width: 100%;">
    <div style="float: left; width : 10%;">
    <asp:Label runat="server" ID="lblSearch" Text="Select Criteria"></asp:Label>
            </div>
            <div style="float: left; width :10%;">
                <asp:DropDownList runat="server" ID="ddlColumn">
    <asp:ListItem Text="First Name" Value="FIRSTNAME"></asp:ListItem>
    <asp:ListItem Text="Last Name" Value="LASTNAME"></asp:ListItem>
    <asp:ListItem Text="Login ID" Value="LOGINNAME"></asp:ListItem>
    <asp:ListItem Text="E-mail ID" Value="EMAIL"></asp:ListItem>
                </asp:DropDownList>
            </div>
      <div style="float: left; width :10%;">
    <asp:Label runat="server" ID="lblValue" Text="Value"></asp:Label>
            </div>
            <div style="float: left; width :15%;">
                <asp:TextBox runat="server" ID="txtValue" ></asp:TextBox>
            </div>
            <div>
                <asp:Button runat="server" ID="btnSearch" Text="Search" 
                    onclick="btnSearch_Click" />
            </div>
    </div>
  • btnSearch:包含从数据库搜索特定数据的代码。从下面的代码可以看出,如果 txtValue 文本字段中有值,它会形成一个 Where 子句,如果不存在,则传递一个空的 Where 子句,这将搜索 Grid 控件的所有记录。
  • protected void btnSearch_Click(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(txtValue.Text))
        {
            grdEmployee.WhereClause = ddlColumn.SelectedValue + 
                                      " like '%" + txtValue.Text + "%'";
        }
        else
        {
            grdEmployee.WhereClause = string.Empty;
        }
        grdEmployee.SelectList = 
          "[FIRSTNAME],[LASTNAME],[LOGINNAME],[EMAIL]";
        grdEmployee.FromClause = "[EMPLOYEE]";
        grdEmployee.BindGrid();    
    }
© . All rights reserved.