GridView是asp.net 2.0中,最常用、最好用的服务器控件之一;但是,为了让它更适应于我们具体的项目,我们很多时候,需要对它进行一些特殊操作。
如,实现如下效果
当然,我承认,实现如上效果并不复杂,
1、增加一个模版列放置复选框;
2、合并底部(footer)并放置三个LinkButton,即全选、反选、取消;并写相应事件,使其可以操作各行中的复选框;
3、然后在OnRowDataBound事件中,给各个行加上JavaScript事件,使各个数据行可以响应鼠标悬停,以及单击事件;
4、当通过其它的操作(如点击删除按钮)来操作数据行时,用foreach遍历各数据行即可;
问题是,我们的项目中,会非常频繁的用到这个效果,作为一个懒人,每次要拷贝代码,实在是太麻烦了。写一个增强的GridView控件,才是明智之举;
如上效果所示,这个增强GridView应该具备以下功能:
1、拖上来就能用,自带一个选择列;这个选择列要能够绑定数据(可选);也就是说,增强控件只能比以前更方便,不能更复杂。
2、footer自动合并,并带三个LinkButton;对复选框操作采用JavaScript方法,在客户端执行,这样无须刷新页面,操作更流畅;
3、能够自动取出选中的行,不必再foreach遍历;
4、带一些参数,可以选择是否显示“选择列”,以及取选中行的主键值;
为了实现以上效果,要写C#,也要写JavaScript与Css;
例如,动态增加模版列,当然得写C#代码操作;利用控件的OnInit事件;
而数据行的鼠标悬停与单击,当然得写JavaScript,用它来操作加载Css样式;这里我用了Jquery框架。
我在这里把主要的C#代码拿出来供学习吧。关键的地方我做了描述,当然,里面有一些代码写得有冗余,也是自己懒,不想在客户端做太多判断,直接标识了数据行,如e.Row.Attributes.Add("RowType","DataRow");,之类的,都是为方便js在客户端判断。
代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace Company.CustomControl
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:GridView runat=server></{0}:GridView>")]
public class GridView : System.Web.UI.WebControls.GridView
{
#region 属性
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("用于选择的复选框所在数据列的,数据列名称,即绑定值")]
[Localizable(true)]
public string SelectBoxKeyName
{
get
{
String s = (String)ViewState["SelectBoxKeyName"];
return ((s == null) ? "SelectBox" : s);
}
set
{
ViewState["SelectBoxKeyName"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("是否显示用于选择的复选框的数据列")]
[Localizable(true)]
public bool ShowSelectBox
{
get
{
String s = (String)ViewState["ShowSelectBox"];
return Convert.ToBoolean(((s == null) ? "True" : s));
}
set
{
ViewState["ShowSelectBox"] = value.ToString();
}
}
/// <summary>
/// 获取选中数据行的主键值
/// </summary>
[Bindable(true)]
[DefaultValue(" 获取选中数据行的主键值")]
[Localizable(true)]
[Category("Appearance")]
public string GetKeyValues
{
get
{
if (this.DataKeyNames.Length < 1)
{
return "";
}
string tmp = "";
foreach (GridViewRow vr in this.Rows)
{
if (vr.RowType == DataControlRowType.DataRow)
{
CheckBox cb = (CheckBox)vr.FindControl(this.SelectBoxKeyName);
if (cb.Checked)
{
tmp += this.DataKeys[vr.RowIndex].Value.ToString() + ",";
}
}
}
if (tmp.IndexOf(",") > -1)
{
tmp = tmp.Substring(0, tmp.LastIndexOf(","));
}
return tmp;
}
}
#endregion
protected override void OnDataBound(EventArgs e)
{
if (this.CssClass == String.Empty)
{
this.CssClass = "GridView";
}
base.OnDataBound(e);
}
protected override void OnInit(EventArgs e)
{
//绑定选择框的列
if (this.ShowSelectBox)
{
TemplateField dcf = new TemplateField();
dcf.HeaderText = "选择";
CheckTemplate mt = new CheckTemplate(this.SelectBoxKeyName);
dcf.ItemTemplate = mt;
this.Columns.Insert(0, dcf);
}
base.OnInit(e);
}
protected override void OnRowDataBound(GridViewRowEventArgs e)
{
//当为数据行时
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes.Add("RowType","DataRow");
//取主键的值
if (this.DataKeyNames != null && this.DataKeyNames.Length>0)
{
string val = this.DataKeys[e.Row.RowIndex].Value.ToString();
e.Row.Attributes.Add("DataKey", val);
}
e.Row.Cells[0].Attributes.Add("ItemType","SelectBox");
}
//底部栏的跨列
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Attributes.Add("RowType", "Footer");
int col = e.Row.Cells.Count;
e.Row.Cells[0].ColumnSpan = col;
while (--col > 0)
{
e.Row.Cells[col].Visible = false;
}
e.Row.Cells[0].Attributes.Add("ItemType", "SelectHandler");
e.Row.Cells[0].Text = "全选、反选、取消";
}
base.OnRowDataBound(e);
}
}
/// <summary>
/// 用于载入复选框的类,该类很重要,是用于自定义GridView模版列的必然方法;
/// </summary>
public class CheckTemplate : ITemplate
{
private string colname;
public CheckTemplate(string colname)
{
this.colname = colname;
}
public void InstantiateIn(Control container)
{
CheckBox cb = new CheckBox();
cb.ID = colname;
cb.CssClass = colname;
cb.Attributes.Add("ControlType", "SelectBox");
cb.DataBinding += new EventHandler(this.OnDataBinding);
container.Controls.Add(cb);
}
public void OnDataBinding(object sender, EventArgs e)
{
try
{
//用于数据绑定
CheckBox cb = (CheckBox)sender;
GridViewRow container = (GridViewRow)cb.NamingContainer;
//如果存在该数据列,则绑定;
cb.Checked = Convert.ToBoolean(((DataRowView)container.DataItem)[colname].ToString());
}
catch
{
//我不是有意要写try,只是当SelectBoxKeyName属性为空时,即用户并不想给选择列绑定数据时,这里不至于出错;
//如果SelectBoxKeyName属性不为空,其数据会自动绑定到选择列上。
}
}
}
}
上面的控件,增加了三个属性;
SelectBoxKeyName:这个是对选择列进行数据绑定时的键值,如DataTable的列名;这个可以不填的。
ShowSelectBox:是否显示的选择列,默认为显示;
GetKeyValues:获取选中数据行的主键值;如果没有主键,或没有选中行,则返回空字符,否则返回主键列表字符串,用逗号分隔;如10,20,55,56;
使用很简单,asp.net页面中代码如下
<%@ Register Assembly="Company.CustomControl" Namespace="Company.CustomControl" TagPrefix="cc1" %>
<cc1:GridView ID="GridView1" runat="server" ShowFooter="True">
</cc1:GridView>
绑定数据后,就显示出如顶部图中的效果。
我抽空把它整理出来,单独放到一个项目中,做个完整示例,发上来吧。以上代码,供参考学习;
完整示例做好了(vs2005 sp1):
GridViewDemo.rar