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

带搜索选项的 ASP.NET GridView (SearchableGridView)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (35投票s)

2009年10月12日

CPOL

3分钟阅读

viewsIcon

266636

downloadIcon

17619

一个在页脚带有搜索选项的 ASP.NET GridView。

引言

我一直在寻找在 ASP.NET GridView 控件中包含搜索文本框选项的方法。 我找不到一个优雅的解决方案,并决定自己实现它。 所以这是我解决这个问题的方法。

为什么要使用此解决方案?

您可以使用此解决方案非常容易地在网格中实现行过滤。 只需处理引发的搜索事件即可执行搜索和过滤操作。 此外,此 GridView 还允许您设置选项以显示行序列号、总行数,并在 GridView 中没有可用行时显示标题和页脚。(默认情况下,当 GridView 没有要显示的行时,标题和页脚是隐藏的。)

解决方案

我所做的事情

  1. 我扩展了 GridView 并创建了一个 SearchableGridView 类。
  2. 添加了一个 TemplateColumn 来显示行号。
  3. 在页脚中添加了控件来处理搜索操作。
  4. 当触发搜索时,引发一个以搜索字符串作为参数的事件。

代码

我将 GridView 控件扩展为 SearchableGridView,以便在 GridView 的页脚中包含搜索选项。

public class SearchGridView : GridView

为了显示行序列号,我创建了以下模板列

public class NumberColumn : ITemplate
{
    public void InstantiateIn(Control container)
    {

    }
}

SearchableGridView 中,我重写了 OnInit 函数,以在 ShowRowNumber 标志打开时添加模板列作为第一列来显示行序列号。

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    //If showrownumber option is turned on then add 
    //the template column as the first column.
    if (!IsDesign() && ShowRowNumber) 
    {
        TemplateField tmpCol = new TemplateField();
        NumberColumn numCol = new NumberColumn();
        tmpCol.ItemTemplate = numCol;
        // Insert this as the first column
        this.Columns.Insert(0, tmpCol);
    }
}

每次创建行时都会调用 OnRowCreated 方法。 在运行时,根据 RowType,我添加搜索控件和行号的标签(在页脚中)、行号(在每一行中)以及行号列的列标题(在标题中)。

protected override void OnRowCreated(GridViewRowEventArgs e)
{
    base.OnRowCreated(e);
    if (!IsDesign()) //During Runtime
    {
        if (e.Row.RowType == DataControlRowType.Footer)
        {
            //If ShowFooter is set to true
            if (ShowFooter && e.Row.Cells.Count > 0)
            {
                //If TotalRows has to be shown
                if (ShowTotalRows)
                {
                    e.Row.Cells[0].Text = ViewState[NO_OF_ROWS] + " Rows.";
                }
                if (e.Row.Cells[e.Row.Cells.Count - 1].Controls.Count == 0)
                {
                    //Create the search control
                    Table table = new Table();
                    table.Style.Add("width", "100%");
                    table.Style.Add("align", "right");
                    TableRow tr = new TableRow();
                    TableCell tc = new TableCell();
                    tc.Style.Add("align", "right");
                    tc.Style.Add("width", "100%");

                    //Populate the dropdownlist with the Ids
                    //of the columns to be filtered
                    if (_ddlFinder.Items.Count == 0)
                        SetFilter();

                    _btnSearch.Width = 20;
                    _btnSearch.Height = 20;
                    _btnSearch.ImageAlign = ImageAlign.AbsMiddle;
                    _btnSearch.AlternateText = "Search";
                    //Assign the function that is called when search button is clicked
                    _btnSearch.Click += new ImageClickEventHandler(_btnSearch_Click);
                    
                    tc.Controls.Add(_ddlFinder);
                    tc.Controls.Add(_tbSearch);
                    tc.Controls.Add(_btnSearch);
                    tr.Cells.Add(tc);
                    table.Rows.Add(tr);

                    _pnlSearchFooter.Controls.Add(table);
                    e.Row.Cells[e.Row.Cells.Count - 1].Controls.Add(_pnlSearchFooter);
                
                }
            }
        }
        if (e.Row.RowType == DataControlRowType.Header)
        {
            // If ShowHeader is set to true and 
            // If Row number has to be shown

            if (ShowRowNumber && ShowHeader) 
            {
                e.Row.Cells[0].Text = "Sno";
            }
        }
        else if (e.Row.RowType == DataControlRowType.DataRow)
        {
            if (ShowRowNumber)
            {
                //Set the row number in every row
                e.Row.Cells[0].Text = (e.Row.RowIndex + 
                  (this.PageSize * this.PageIndex) + 1).ToString();
            }
        }
    }
}

SearchableGridViewSearchFilters 属性设置搜索选项的下拉列表值。 列表项的 Text 属性对应于下拉列表中的显示名称,列表项的 Value 属性是数据源的列名。

public void SetFilter()
{
    _ddlFinder.Items.Clear();
    //Copy the items to the dropdownlist
    foreach (ListItem li in SearchFilters)
        _ddlFinder.Items.Add(li);
}

现在,让我们继续处理搜索事件。 为此,我创建了一个委托并在点击搜索按钮时触发 SearchGrid 事件。 搜索字符串使用语法 _ddlFinder.SelectedValue + " like '" + _tbSearch.Text.Trim() + "%'" 形成。

public delegate void SearchGridEventHandler(string _strSearch);
public event SearchGridEventHandler SearchGrid;

void _btnSearch_Click(object sender, ImageClickEventArgs e)
{
    string sSearchText = ConstructSearchString();
    OnSearchGrid(sSearchText);
}

protected string ConstructSearchString()
{
    string _strText = _tbSearch.Text.Trim();

    if (_strText == string.Empty)
        return string.Empty;

    return _ddlFinder.SelectedValue + " like '" + _strText + "%'";
}

protected void OnSearchGrid(string _strSearch)
{
    if (SearchGrid != null)
    {
        SearchGrid(_strSearch);
    }
}

当没有返回任何行时显示页脚

GridView 的默认属性是在没有绑定任何行时隐藏标题和页脚。 设置一个空的 item 模板只会显示模板,而不会显示标题或页脚。 在我们的例子中,无论绑定到 SearchableGridView 的行数是多少,都必须始终显示页脚,因为搜索选项应该是可见的。 为了实现这一点,我必须重写 CreateChildControls 方法,如下所示

protected override int CreateChildControls(System.Collections.IEnumerable dataSource, 
                                           bool dataBinding)
{
    int count = base.CreateChildControls(dataSource, dataBinding);

    //  no rows in grid. create header and footer in this case
    if (count == 0 && (ShowEmptyFooter || ShowEmptyHeader))
    {
        //  create the table
        Table table = this.CreateChildTable();

        DataControlField[] fields;
        if (this.AutoGenerateColumns)
        {
            PagedDataSource source = new PagedDataSource();
            source.DataSource = dataSource;

            System.Collections.ICollection autoGeneratedColumns = 
                                           this.CreateColumns(source, true);
            fields = new DataControlField[autoGeneratedColumns.Count];
            autoGeneratedColumns.CopyTo(fields, 0);
        }
        else
        {
            fields = new DataControlField[this.Columns.Count];
            this.Columns.CopyTo(fields, 0);
        }

        if (ShowEmptyHeader)
        {
            //  create a new header row
            GridViewRow headerRow = base.CreateRow(-1, -1, DataControlRowType.Header, 
                                                   DataControlRowState.Normal);
            this.InitializeRow(headerRow, fields);
            // Fire the OnRowCreated event to handle showing row numbers
            OnRowCreated(new GridViewRowEventArgs(headerRow));
            //  add the header row to the table
            table.Rows.Add(headerRow);
        }

        //  create the empty row
        GridViewRow emptyRow = new GridViewRow(-1, -1, DataControlRowType.EmptyDataRow, 
                                               DataControlRowState.Normal);
        TableCell cell = new TableCell();
        cell.ColumnSpan = fields.Length;
        cell.Width = Unit.Percentage(100);

        //  respect the precedence order if both EmptyDataTemplate
        //  and EmptyDataText are both supplied ...
        if (this.EmptyDataTemplate != null)
        {
            this.EmptyDataTemplate.InstantiateIn(cell);
        }
        else if (!string.IsNullOrEmpty(this.EmptyDataText))
        {
            cell.Controls.Add(new LiteralControl(EmptyDataText));
        }

        emptyRow.Cells.Add(cell);
        table.Rows.Add(emptyRow);

        if (ShowEmptyFooter)
        {
            //  create footer row
            GridViewRow footerRow = base.CreateRow(-1, -1, DataControlRowType.Footer, 
                                                   DataControlRowState.Normal);
            this.InitializeRow(footerRow, fields);
            // Fire the OnRowCreated event to handle showing
            // search tool and total number of rows
            OnRowCreated(new GridViewRowEventArgs(footerRow));

            //  add the footer to the table
            table.Rows.Add(footerRow);
        }

        this.Controls.Clear();
        this.Controls.Add(table);
    }

    return count;
}

工作示例

让我借助一个例子来说明上面的控件。 为此,我使用了 NorthWind 数据库中的 Customers 表。

步骤 1:创建一个带有 Select 查询的数据源 dsCustomers:"SELECT CustomerID, CompanyName, Address, City, Country FROM Customers"。

步骤 2:创建一个 SearchableGridView 实例并自定义 SearchFilters 属性,以拥有可以在其上执行搜索的列的列表。

步骤 3:添加两个隐藏字段 hfSearchTexthfSort,以分别存储搜索文本和排序文本。

步骤 4:实现 SearchGrid 事件以在数据源上设置搜索字符串,并在 SearchableGridView 中过滤行。 hfSearchTexthfSort 是保存 SearchableGridView 的搜索字符串和排序字符串的隐藏字段。 BindData 方法在过滤和排序后绑定数据。

protected void SearchGridView1_SearchGrid(string _strSearch)
{
    hfSearchText.Value = _strSearch;
    BindData();
}

protected void SearchGridView1_Sorting(object sender, GridViewSortEventArgs e)
{
    //If hfSort has the same value as before, 
    //the sorting should be done in descending order
    if (hfSort.Value == e.SortExpression)
        hfSort.Value = e.SortExpression + " Desc";
    else
        hfSort.Value = e.SortExpression;
    BindData();
}

void BindData()
{
    //hfSearchText has the search string returned from the grid.
    if (hfSearchText.Value != "")
        dsCustomers.SelectCommand += " where " + hfSearchText.Value;
    DataView dv = (DataView)dsCustomers.Select(new DataSourceSelectArguments());
    //hfSort has the sort string returned from the grid.
    if (hfSort.Value != "")
        dv.Sort = hfSort.Value;

    SearchGridView1.DataSource = dv;
    try
    {
        SearchGridView1.DataBind();
    }
    catch (Exception exp)
    {
        //If databinding threw exception b’coz current 
        //page index is > than available page index
        SearchGridView1.PageIndex = 0;
        SearchGridView1.DataBind();
    }
    finally
    {
        //Select the first row returned
        if (SearchGridView1.Rows.Count > 0)
            SearchGridView1.SelectedIndex = 0;
    }
}

结论

当网格中有大量行时,SearchableGridView 将非常有用。 无需太多麻烦即可实现搜索行。

© . All rights reserved.