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

GridView 按需数据填充、自定义分页、客户端排序和其他通用功能

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2013年7月4日

CPOL

6分钟阅读

viewsIcon

35534

downloadIcon

538

一篇介绍 GridView 通用功能的文章。

引言

本文将介绍 GridView 控件日常任务的实现。开发人员几乎每天都会遇到这些需求。目标是将所有这些常规任务汇集到一个地方。阅读完本文后,您将了解如何

  • 按需填充数据。 
  • 添加具有多列的记录(比 GridView 显示的列多) 
  • 在同一页面上编辑 GridView 数据并进行验证。
  • 自定义分页。
  • 客户端排序。 
  • 搜索。 
  • 全选/取消全选记录(客户端)
  • 在 GridView 的 itemtemplate 字段中根据条件显示图像。 

背景

说实话,我几个月前就开始考虑写这篇文章了。如果您访问本网站的快速答案部分,您会注意到有关 GridView 控件的问题很多。在我看来,GridView 是表示表格数据时最常用的控件,开发人员毫不犹豫地尽可能多地使用它。显然,我们作为开发人员需要定期实现排序、搜索记录、自定义分页、添加、删除、更新等功能。有时用户最初只想在 GridView 中显示几列,但在单击某一行或某一列时,希望显示全部/剩余的详细信息。  

大多数情况下,开发人员会采取两种方法(我遇到过并讨论过)。   

  • 在父 GridView 中添加一个子 GridView 作为 itemtemplate,并使用 rowdatabound 事件来填充它。 
  • 打开一个弹出窗口,根据通过 querystring 传递的行 ID 显示详细信息。

第一种方法的缺点是成本很高。每次用数据库中的数据填充一行时,都会进行另一个调用来填充子 GridView。这会增加开销,并严重影响应用程序的性能。

第二种方法看起来不太好,尽管它有效,但总会有弹出窗口拦截器可能会搞砸一切。而且  如果客户端系统的安全设置根据其便利性进行了调整,则根本看不到打开的弹出窗口。  

那么,解决方案是什么?jQuery。我们将使用 jQuery 的 $.ajax() 方法以 JSON 格式获取详细信息,并将内容填充到模态弹出窗口中。   

使用代码

首先,创建一个数据库并在源代码中的 script.txt 文件中运行脚本。修改您的连接字符串,我们就可以开始了。

显示用户详细信息

我们要创建的第一个是 HTTPHandler。此处理程序将以 JSON 格式为我们提供选定用户的详细信息。这也可以通过网页完成,但 HTTPHandlers 对于此类需求总是很好的,因为它们速度很快。它们不必经历页面生命周期。因此,在此 HTTPHandler 中,我们将添加一个类和属性。 

public class User
{
    public string EDCode { get; set; }
    public string EDFirstName { get; set; }
    public string EDLastName { get; set; }
    public string EDDOB { get; set; }
    public string EDCellPhoneNumber { get; set; }
    public string EDLandlineNumber { get; set; }
    public string EDEmailID { get; set; }
    public string EDAddress { get; set; }
    public string EDImagePath { get; set; }
    public string EDExperience { get; set; }
    public string EDSkills { get; set; }
    public string EDDesignation { get; set; }
    public string EDPreviousCompany { get; set; }
    public string EDDOJ { get; set; }
    public string EDIsPermanent { get; set; }
    public string EDIsReportingManager { get; set; }
    public string EDDOB_MMDDYYYY { get; set; }
    public string EDDOJ_MMDDYYYY { get; set; }
}

现在是时候填充数据了。为此,函数编写如下

private User GetUserDetails(int Id)
{
    var user = new User();
    using (SqlConnection con = new SqlConnection(
      System.Web.Configuration.WebConfigurationManager.ConnectionStrings[
      "SqlConnection"].ConnectionString))
    {
        con.Open();
        DataTable dtFiles = new DataTable();
        SqlCommand com = new SqlCommand("SP_GetCompleteUserDetails", con);
        com.CommandType = CommandType.StoredProcedure;
        com.Parameters.AddWithValue("@userid", Id);
        SqlDataReader dr = com.ExecuteReader();
        if (dr.HasRows)
        {
            dr.Read();
            user.EDCode = dr["ED_Code"].ToString().Trim();
            user.EDFirstName = dr["ED_FirstName"].ToString().Trim();
            user.EDLastName = dr["ED_LastName"].ToString().Trim();
            user.EDDOB = dr["ED_DOB"].ToString().Trim();
            user.EDDOB_MMDDYYYY = Convert.ToDateTime(dr["ED_DOB"]).ToString("MM/dd/yyyy");
            user.EDCellPhoneNumber = dr["ED_CellPhoneNumber"].ToString().Trim();
            user.EDLandlineNumber = dr["ED_LandlineNumber"].ToString().Trim();
            user.EDEmailID = dr["ED_EmailID"].ToString().Trim();
            user.EDAddress = dr["ED_Address"].ToString().Trim();
            user.EDImagePath = dr["ED_ImagePath"].ToString().Trim();
            user.EDExperience = dr["ED_Experience"].ToString().Trim();
            user.EDSkills = dr["ED_Skills"].ToString().Trim();
            user.EDDesignation = dr["ED_Designation"].ToString().Trim();
            user.EDPreviousCompany = dr["ED_PreviousCompany"].ToString().Trim();
            user.EDDOJ = dr["ED_DOJ"].ToString().Trim();
            user.EDDOJ_MMDDYYYY = Convert.ToDateTime(dr["ED_DOJ"]).ToString("MM/dd/yyyy");
            user.EDIsPermanent = dr["ED_IsPermanent"].ToString().Trim();
            user.EDIsReportingManager = dr["ED_IsReportingManager"].ToString().Trim();
        }
    }
    return user;
}

现在,当我们拥有 User 类的对象时,我们将将其序列化为 JSON 对象,我们的 HTTPHandler 将返回此对象,我们稍后将使用它来显示所选用户的详细信息。序列化和返回 JSON 对象的代码如下

public void ProcessRequest(HttpContext context)
{
    var userDetails = GetUserDetails(Convert.ToInt32(context.Request["EID"].Trim()));
    JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
    string serializedUserDetails = javaScriptSerializer.Serialize(userDetails);
    context.Response.ContentType = "text/html";
    context.Response.Write(serializedUserDetails);
}

上面的代码是不言自明的。我们所做的就是从数据库中获取详细信息并将其转换为 JSON 对象。现在来看看实际情况:如何在我们的页面上显示这些详细信息。

我在 GridView 的 itemtemplate 中添加了一个标签,并从代码隐藏为其添加了一个属性。标签的标记是: 

<asp:Label ID="linkDetails" 
  runat="server" Text='<%# Eval("ED_Code") %>' 
  CssClass="userDetails"></asp:Label>

在 GridView 的 rowdatabound 事件中,我们添加了 onclick 属性,如下所示

protected void GridViewUsers_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        DataRowView rowView = (DataRowView)e.Row.DataItem;
        string rowID = rowView["ED_ID"].ToString();
        Label linkDetails = new Label();
        Button btnEditRow = new Button();
        linkDetails = (Label)e.Row.FindControl("linkDetails");
        btnEditRow = (Button)e.Row.FindControl("btnEditRow");
        linkDetails.Attributes.Add("onclick", 
          "getDetails('" + rowID + "');");
        btnEditRow.Attributes.Add("onclick", 
          "return getDetailsToEdit('" + rowID + "');");
    }
} 

在上面的代码中,我为两个控件添加了 onclick 属性。linkDetails 将用于显示所选用户的详细信息,而 btnEditRow 是我用来编辑详细信息的按钮。编辑也将以相同的方式完成(模态弹出窗口)。

互联网上有很多模态弹出窗口。我使用的是 reveal 模态弹出窗口。它轻量级、可配置且非常易于使用。您所要做的就是将模态弹出窗口的内容包装在一个 div 中,然后调用 JavaScript 方法在 pageLoad 或元素单击时显示模态弹出窗口。您可以从 http://zurb.com/playground/reveal-modal-plugin 下载它 

获取详细信息的函数如下编写: 

function getDetails(objID) {
    $.ajax({
        url: "AjaxRequestHandler.ashx",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: { 'EID': objID },
        responseType: "json",
        success: OnComplete,
        error: OnFail
    });
}

成功收到 JSON 对象后,将调用 OnComplete 函数,它将填充 div 内容。OnComplete 函数的实现如下

function OnComplete(result) {
    $('#UserDetails').reveal({
        animation: 'fadeAndPop',
        animationspeed: 300,
        closeonbackgroundclick: false,
        dismissmodalclass: 'close-reveal-modal'
    });
    $('#userid').text(result.EDCode);
    $('#username').text(result.EDFirstName + ' ' + result.EDLastName);
    $('#userdob').text(result.EDDOB);
    $('#usercellnumber').text(result.EDCellPhoneNumber);
    $('#userlandlinenumber').text(result.EDLandlineNumber);
    $('#useremailid').text(result.EDEmailID);
    $('#useraddress').text(result.EDAddress);
    $('#userexperience').text(result.EDExperience);
    $('#userskills').text(result.EDSkills);
    $('#userdesignation').text(result.EDDesignation);
    $('#userpreviouscompany').text(result.EDPreviousCompany);
    $('#userdoj').text(result.EDDOJ);
    $('#userpermanent').text(result.EDIsPermanent);
    $('#userreportingmanager').text(result.EDIsReportingManager);
    $("#userImage").attr("src", 'UserImages/' + result.EDImagePath);
}

现在,当您运行此程序并单击 Employee ID 时,您将得到以下格式的结果

Details

同样,编辑/添加也完成了。记录的添加/更新也使用相同的模态弹出窗口完成。结果将如下所示

Add or Edit 

实现客户端的选中/取消选中功能

对于选中/取消选中功能,我使用了 jQuery。原因是在 GridView 中查找复选框并用一行代码为所有复选框应用属性非常容易,而不是使用 databound 事件为每个复选框应用属性。代码相当简单。

var selectAllCheckBox = '#<%=GridViewUsers.ClientID%> input[id*="chkAllEmployee"]:checkbox';
var selectEmployeeCheckBox = '#<%=GridViewUsers.ClientID%> input[id*="CheckBoxEmployeeID"]:checkbox';
 
function CheckUncheckAll() {
var totalCheckboxes = $(selectEmployeeCheckBox);
var checkedCheckboxes = totalCheckboxes.filter(":checked");
var allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
$(selectAllCheckBox).attr('checked', allCheckboxesAreChecked);
}
 
function pageLoad() {
$(selectAllCheckBox).live('click', function () {
$(selectEmployeeCheckBox).attr('checked', $(this).is(':checked'));
CheckUncheckAll();
});
$(selectEmployeeCheckBox).live('click', CheckUncheckAll);
CheckUncheckAll();  

上面代码的第一行用于查找 GridView 页眉中的复选框,第二行用于查找所有 ID 为“CheckBoxEmployeeID”的复选框(这些是每一行的复选框)。

接下来有一个函数“CheckUncheckAll”。此函数查找所有复选框,并根据页眉复选框的属性,将 GridView 行中复选框的属性设置为页眉复选框的选中状态。此函数在 pageLoad 方法中调用,以便我们在部分回发时不会丢失绑定。 

实现客户端排序

客户端排序是使用 jQuery TableSorter 插件实现的。它可以在 http://tablesorter.com/docs/ 找到。

使用此插件时,唯一重要的是它适用于带有 <THEAD> 和 <TBODY> 标签的 HTML 表,而 GridView 默认不会用这些标签呈现。我们将编写一些代码来生成这些标签。 为此,在将数据绑定到 GridView 后,添加以下代码

if (GridViewUsers.Rows.Count > 0)
{
	GridViewUsers.UseAccessibleHeader = true;
	GridViewUsers.HeaderRow.TableSection = TableRowSection.TableHeader;
	GridViewUsers.FooterRow.TableSection = TableRowSection.TableFooter;
}

实现自定义分页

作为开发人员,我们应始终考虑应用程序的性能。使用 GridView 时,一种常见做法是使用 GridView 自带的默认分页功能。假设您的查询返回 10000 条记录,而 GridView 的页面大小为 50,在初始页面上您将看到 50 条记录,其余 9950 条记录将被截断。这不是个好主意。您可以编写查询,使其仅返回所需的行。幸运的是,SQL Server 中有一个 rowcount 属性可以派上用场。我们将传递页索引和要获取的记录数,存储过程将只返回 这些行。存储过程的脚本可以在源代码中找到,SQL 代码非常简单易懂。 

关注点

我已尽力使代码尽可能简单。示例代码仍有改进的空间。欢迎提出建议和批评。希望您会发现本文很有帮助。有关源代码的任何解释和疑问,请随时评论。

© . All rights reserved.