LINQ TO SQL GridView(增强的 Gridview)






4.88/5 (49投票s)
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 文件,用于演示网格控件。
第 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
泛型属性,它返回类型T
的System.Data.Linq.Table
。MyDataContext
是由 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) {如果
whereClause
和orderBy
都不为null
且不为空,则它应用wherecondition
进行过滤,并应用orderby
对实体列表进行排序。if (!string.IsNullOrEmpty(whereClause) && !string.IsNullOrEmpty(orderBy)) { return getAllEntity.Where(whereClause).OrderBy(orderBy).Skip(startRowIndex * maximumRows).Take(maximumRows); }如果
whereClause
为null
或空,并且orderBy
不为null
且不为空,则应用orderby
对实体列表进行排序。else if (string.IsNullOrEmpty(whereClause) && !string.IsNullOrEmpty(orderBy)) { return getAllEntity.OrderBy(orderBy).Skip(startRowIndex * maximumRows).Take(maximumRows); }如果
orderBy
为null
或空,并且whereClause
不为null
且不为空,则应用wherecondition
对实体列表进行过滤。else if (!string.IsNullOrEmpty(whereClause) && string.IsNullOrEmpty(orderBy)) { return getAllEntity.Where(whereClause).Skip(startRowIndex * maximumRows).Take(maximumRows); }如果
orderBy
和whereClause
都为null
或空,则返回实体列表。else { return getAllEntity.Skip(startRowIndex * maximumRows).Take(maximumRows); }以下两个方法在支持网格视图控件的按需分页方面起着重要作用。
}
}
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 的信息。