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

LINQ TO SQL GridView(增强的 Gridview)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (49投票s)

2010年7月11日

CPOL

6分钟阅读

viewsIcon

177518

downloadIcon

2399

LINQ TO SQL 增强的 Gridview。

引言

如今,大多数开发人员都使用 LINQ 2 SQL 创建新的 Web 或 Windows 应用程序。在本文中,我将讨论如何构建支持任何 LINQ 2 SQL 应用程序结构的自定义 GridView 控件。

Grid view 控件具有以下功能

  • 支持 Linq 2 SQL
  • 使用 Linq 2 SQL 实现自定义分页
  • 显示排序方向
  • 页面导航器中的下拉列表,用于调整每页记录数

实现

该应用程序分为三层。

第 1 层:LINQ to SQL 数据访问层

此层包含由 Visual Studio 根据所选数据库生成的 DBML 文件,用于演示网格控件。

DataBase

第 2 层:业务层

它由三个文件组成

Dynamic - 包含支持动态 linq 执行的类的实现。(参见此链接)。
EntityList - 包含 Generic 类的实现,用于获取要在网格视图控件中显示的数据。
LinqGridView - 包含自定义网格视图控件的实现。

EntityList.CS

声明具有泛型类型 T 的泛型实体 EntityList 类。(其中 T : class 表示类型参数必须是引用类型;这也适用于任何类、接口、委托或数组类型。)

public class EntityList<T> where T : class 
{ 
   public EntityList() 
   { 
      // 
     // TODO: Add constructor logic here 
     // 
   } 

属性

getAllEntity - 列出类型 T 的所有实体。

以下代码行声明了一个 static 泛型属性,它返回类型 TSystem.Data.Linq.TableMyDataContext 是由 Visual Studio 生成的 datacontext 类,用于调用 DataAccess 层的 GetTable 方法以获取类型 T 的实体。

public static System.Data.Linq.Table<T> getAllEntity 
{ 
  get 
  { 
      MyDataContext db = new MyDataContext(); 
      return db.GetTable<T>(); 
   } 
} 

DataContext:表示 LINQ to SQL 框架的主要入口点。(参见此链接)。

方法

GetCount - 用于获取实体总数的方法。

public static int GetCount(string whereClause) 
{ 
  if (!string.IsNullOrEmpty(whereClause)) 
     return getAllEntity.Where(whereClause).Count(); 
  else 
     return getAllEntity.Count(); 
}

whereClause - 如果条件不为空或 null,则方法返回按 where 子句过滤的记录计数。如果为 null 或空,则返回未过滤条件的记录计数。

GetEntityByPage - 用于按页获取实体列表的方法,即支持网格视图控件中的按需分页。

  • startRowIndex - 起始行索引,即数字
  • maximumRows - 一页中的行数
  • whereClause - 过滤记录的条件
  • orderBy - 列名,带升序或降序。
public static IQueryable<T> GetEntityByPage
(int startRowIndex, int maximumRows, string whereClause, string orderBy) 
{ 

如果 whereClauseorderBy 都不为 null 且不为空,则它应用 wherecondition 进行过滤,并应用 orderby 对实体列表进行排序。

if (!string.IsNullOrEmpty(whereClause) && !string.IsNullOrEmpty(orderBy)) 
{ 
      return getAllEntity.Where(whereClause).OrderBy(orderBy).Skip(startRowIndex  
                * maximumRows).Take(maximumRows); 
} 

如果 whereClausenull 或空,并且 orderBy 不为 null 且不为空,则应用 orderby 对实体列表进行排序。

else if (string.IsNullOrEmpty(whereClause) && !string.IsNullOrEmpty(orderBy)) 
{ 
       return getAllEntity.OrderBy(orderBy).Skip(startRowIndex 
                * maximumRows).Take(maximumRows); 
}

如果 orderBynull 或空,并且 whereClause 不为 null 且不为空,则应用 wherecondition 对实体列表进行过滤。

else if (!string.IsNullOrEmpty(whereClause) && string.IsNullOrEmpty(orderBy)) 
{ 
       return getAllEntity.Where(whereClause).Skip(startRowIndex 
                * maximumRows).Take(maximumRows); 
} 

如果 orderBywhereClause 都为 null 或空,则返回实体列表。

else 
{ 
       return getAllEntity.Skip(startRowIndex * maximumRows).Take(maximumRows); 
} 

以下两个方法在支持网格视图控件的按需分页方面起着重要作用。

    • Skip:跳过序列中指定数量的元素,然后返回剩余的元素。(参见此链接)。
    • Take:从序列的开头返回指定数量的连续元素。(参见此链接)。
   } 
}

LinqGridView.cs

public class LinqGridView : GridView 
{ 

属性

lbltotal - 网格的属性,用于存储检索到的记录总数。它用于相应地调整分页。

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; 
      } 
} 

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; 
     } 
} 

DefaultSortExp - 存储默认排序表达式,网格在第一次排序事件发生前用于排序。

private string _DefaultSortExp;; 
public string DefaultSortExp 
{ 
     set 
     { 
        _DefaultSortExp = value; 
     } 
     get 
     { 
         return _DefaultSortExp; 
     } 
} 

typeHolder - 属性保存绑定到网格视图控件的实体类型。

private Type typeHolder 
{ 
     get 
     { 
        if (null != ViewState["typeHolder" + ControlID]) 
           return (Type)ViewState["typeHolder" + ControlID]; 
        else 
          return null; 
      } 
      set 
      { 
        ViewState["typeHolder" + ControlID] = value; 
      } 
}

方法

Bindgrid - 将信息类中的集合绑定到网格视图的方法。

public void BindGrid<T>() where T : class 
{ 
    try 
    { 

以下内容将类的类型存储在 typeHolder 变量中,该变量稍后用于在排序和搜索发生时将网格与类型绑定。

           if (null == typeHolder) 
             typeHolder = typeof(T); 

以下代码行存储分配给网格的排序表达式默认表达式,并存储网格的 pageIndex

            if (string.IsNullOrEmpty(lblSortExp)) 
               lblSortExp = DefaultSortExp; 
            lblpageIndex = this.PageIndex; 

创建并存储 orderby 表达式,该表达式又被 linq 查询信息类集合使用。

            string orderby = 
            "" + lblSortExp + " " + (lblSortDirection == string.Empty ? 
		" asc" : lblSortDirection);   
		lbltotal = EntityList<T>.GetCount(WhereClause); 
            this.DataSource = EntityList<T>.GetEntityByPage
		(PageIndex, PageSize, WhereClause, orderby); 
            this.DataBind(); 
     } 
     catch (Exception ex) { } 
} 

InitializePager - 重写以在 gridview 控件中提供自定义分页。

protected override void InitializePager
	(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource) 
{ 
   try 
   { 
      #region code for standard paging 

将自定义分页属性设置为 true,这允许为分页设置自定义数据源。

      pagedDataSource.AllowCustomPaging = true;

设置自定义数据源检索到的记录总数。

        pagedDataSource.VirtualCount = Convert.ToInt32(lbltotal);

为自定义数据源设置当前页索引。

          pagedDataSource.CurrentPageIndex = lblpageIndex; 
        #endregion code for standard paging 

为网格视图控件设置自定义数据源。

            base.InitializePager(row, columnSpan, pagedDataSource); 
      } 
     catch (Exception ex) { } 
} 

OnRowCreated - 重写以提供 Dropdown,允许用户更改分页以设置 gridview 控件中每页的记录数。此方法也被重写以在网格的标题行中显示排序图标。

protected override void OnRowCreated(GridViewRowEventArgs e) 
{ 
     try 
     { 

获取排序列索引并在网格控件的标题中设置排序图标。

             #region set the icon in header row 
             if (e.Row.RowType == DataControlRowType.Header) 
             { 
                 int index = GetSortColumnIndex(); 
                 if (index != -1) 
                   sortingIcon(index, e.Row); 
              } 
             #endregion set the icon in header row 

向网格的页行添加下拉框控件,以设置每页记录数。

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

创建下拉控件并添加各种页面大小。

                    DropDownList ddl = new DropDownList(); 
                    ddl.Items.Add("5"); 
                    ddl.Items.Add("10"); 
                    ddl.AutoPostBack = true;

在下拉框中设置最终用户选择的 pagesize

                      ListItem li = ddl.Items.FindByText(this.PageSize.ToString()); 
                      if (li != null) 
                        ddl.SelectedIndex = ddl.Items.IndexOf(li); 
                      ddl.SelectedIndexChanged -= 
			new EventHandle(ddl_SelectedIndexChanged); 
                     ddl.SelectedIndexChanged += 
			new EventHandler(ddl_SelectedIndexChanged); 

以下代码行将表单元格添加到网格视图的页行,其中包含一个下拉列表,用于设置每页记录数。

                        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(ddl); 
                        pagerTable.Rows[0].Cells.Add(cell); 
                 } 
     } 
     catch (Exception ex) 
     { } 
    base.OnRowCreated(e); 
} 

ddl_SelectedIndexChanged - 附加到分页下拉框控件,当页面大小更改时触发。

void ddl_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     if (this.PageSize > int.Parse(((DropDownList)sender).SelectedValue)) 
       IsIndexChange = true; 
    else 
       IsIndexChange = false; 
    this.PageIndex = 0; 
    //changes page size 
    this.PageSize = int.Parse(((DropDownList)sender).SelectedValue); 

当下拉框中的页面大小更改时,代码使用反射调用网格的泛型 Bind 方法,以再次将记录绑定到 gridview

    MethodInfo method = this.GetType().GetMethod("BindGrid"); 
    MethodInfo generic = method.MakeGenericMethod(typeHolder); 
    generic.Invoke(this, null); 
} 

OnSorting - 重写以在排序事件发生时(由用户对网格视图控件的记录进行排序)在网格列上设置排序图标。

protected override void OnSorting(GridViewSortEventArgs e) 
{ 
     try 
     { 

代码行将最后一个表达式存储在 lblSortExp 变量中。

             lblSortExp = e.SortExpression; 
             switch (lblSortDirection) 
             { 
                case "asc": 
                { 
                    lblSortDirection = "desc"; 
                    break; 
                } 
                case "desc": 
                case "": 
                case null: 
                { 
                    lblSortDirection = "asc"; 
                    break; 
                } 
              } 

在排序事件发生后,调用网格的 bind 方法以将记录绑定到 gridview

               MethodInfo method = this.GetType().GetMethod("BindGrid"); 
               MethodInfo generic = method.MakeGenericMethod(typeHolder); 
               generic.Invoke(this, null); 
         } 
        catch (Exception ex) { } 
} 

OnPageIndexChanging - 重写以使用更新的页索引再次将网格与记录绑定。

protected override void OnPageIndexChanging(GridViewPageEventArgs e) 
{ 
     try 
     { 
         if (!IsIndexChange) 
         { 
            PageIndex = e.NewPageIndex; 
            MethodInfo method = this.GetType().GetMethod("BindGrid"); 
            MethodInfo generic = method.MakeGenericMethod(typeHolder); 
            generic.Invoke(this, null); 
            base.OnPageIndexChanged(e); 
          } 
          else 
            IsIndexChange = false; 
      } 
      catch (Exception ex) { } 
} 

sortingIcon - 用于将排序图标设置为标题列。

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; 
}
} 

第 3 层:表示层

此层实际讨论了如何在任何使用 linq to SQL 的应用程序中使用自定义 gridview 控件。

Default.aspx

这行代码注册了自定义控件,该控件是 businesslayer 的一部分。

<%@ Register TagPrefix="CC" Namespace="ComponentControls" 
	Assembly="BusinessLayer" %> Below line of the code utilize 
	custom gridview by binding it with the employee class of the 
	datacontext layer. Here first template column used to display 
	no with the records like the rownumber and other template column 
	bind the property of the class to display it.

以下代码行通过将其与 datacontext 层的 employee 类绑定来利用自定义 gridview。在这里,第一个模板列用于显示带记录的数字,例如 rownumber,其他模板列绑定类的属性以显示它。]

<CC:LinqGridView runat="server" DataKeyNames="pkey" 
	AutoUpdateAfterCallBack="true" Width="100%" ID="grduser" 
	AutoGenerateColumns="False" AllowPaging="true" AllowSorting="true" 
	DefaultSortExp="FirstName"> 
  <Columns> 
       <asp:TemplateField HeaderText="No." ItemStyle-HorizontalAlign="Center">
          <ItemTemplate> 
             <%#String.Format("{0}", (((GridViewRow)Container).RowIndex + 1) +  
		(grduser.lblpageIndex * 10))%> 
           </ItemTemplate> 
           <ItemStyle Width="2%" /> 
       </asp:TemplateField> 
    <asp:BoundField HeaderText="FirstName" DataField="FirstName" 
	SortExpression="FirstName" ReadOnly="true" HeaderStyle-Width="120px" 
	ItemStyle-Width="120px" /> 
    <asp:BoundField HeaderText="LastName" DataField="LastName" 
	SortExpression="LastName" ReadOnly="true" HeaderStyle-Width="120px" 
	ItemStyle-Width="120px" /> 
    <asp:BoundField HeaderText="LOGINNAME" DataField="LOGINNAME" 
	SortExpression="LOGINNAME" ReadOnly="true" HeaderStyle-Width="120px" 
	ItemStyle-Width="120px" /> 
   <asp:BoundField HeaderText="EMAIL" DataField="EMAIL" SortExpression="EMAIL" 
	ReadOnly="true" HeaderStyle-Width="120px" ItemStyle-Width="120px" /> 
 </Columns> 
 <PagerSettings Mode="NumericFirstLast" Position="Top" PageButtonCount="5" /> 
 <PagerStyle BackColor="Pink" /> 
</CC:LinqGridView> 

Default.aspx.cs

在此文件中,有两行代码用于绑定 gridview 控件。当页面加载时,它调用 BindGrid 方法,该方法又调用自定义网格的 BindGrid 方法,通过在泛型类型括号中传递 Employee 来绑定 Employee 实体。

protected void Page_Load(object sender, EventArgs e) 
{ 
   if (!IsPostBack) 
  { 
     BindGrid(); 
   } 
} 

/// <summary> 
/// Method to bind datagrid of user. 
/// </summary> 
private void BindGrid() 
{ 
  try 
  { 
     grduser.BindGrid<Employee>(); 
   } 
   catch (Exception ex) 
   { } 
}

结论

此网格控件实现提供了自定义控件的基本实现,并提供了有关 Linq to SQL 的信息。

© . All rights reserved.