public class TGridView : GridView
{
#region 可以进行多项选择
#region 对应选择的项目
#region "全选在那列"
[Browsable(true)]
[DefaultValue(0)]
public int CheckBoxIndex
{
get
{
object obj = this.ViewState["CheckBoxIndex"];
if (obj != null)
{
return (int)obj;
}
return 0;
}
set
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("value");
}
this.ViewState["CheckBoxIndex"] = value;
}
}
#endregion
#region 是否添加选择栏位
[Browsable(true)]
[DefaultValue(false)]
public bool AddCheckBox
{
get;
set;
}
#endregion
/// <summary>
/// 全选是否
/// </summary>
public bool? AllSelect
{
get
{
object obj = this.ViewState["AllSelect"];
if (obj != null)
{
return (bool)obj;
}
return null;
}
set
{
object obj = this.ViewState["AllSelect"];
if (value != null)
{
this.ViewState["AllSelect"] = value;
}
else
{
this.ViewState["AllSelect"] = null;
}
}
}
/// <summary>
/// 记录对应的主键信息(没全选时记录选上的,全选后记录没被选上的)
/// </summary>
public string MarkerID
{
get
{
object obj = this.ViewState["MarkerID"];
return obj == null ? string.Empty : (string)obj;
}
private set
{
if (!object.Equals(value, this.ViewState["MarkerID"]))
{
this.ViewState["MarkerID"] = value;
}
}
}
#endregion
#region 初始化信息
/// <summary>
/// 创建一列为CheckBox的栏位
/// </summary>
/// <param name="dataSource"></param>
/// <param name="useDataSource"></param>
/// <returns></returns>
protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)
{
ArrayList list = base.CreateColumns(dataSource, useDataSource) as ArrayList;
if (AddCheckBox)
{
SelectDataField select = new SelectDataField();
select.CheckboxChanged += new SelectDataField.CheckboxChangedEventHandler(select_CheckboxChanged);
list.Insert(CheckBoxIndex, select);
}
return list;
}
/// <summary>
/// 当全选后先清空前面记录的主键信息,然后更新对应CheckBox的值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void select_CheckboxChanged(object sender, EventArgs e)
{
CheckBox box = sender as CheckBox;
AllSelect = box.Checked;
MarkerID = string.Empty;
UpdateGridViewSelect();
}
#endregion
#region 保持页面CheckBox的状态
/// <summary>
/// 每次分页操作前执行或收集对应结果的CheckBox的值调用
/// </summary>
public void CheckGridViewSelect()
{
if (DataKeyNames.Length < 1)
throw new Exception("GridView没有设置DataKeyNames");
string markids = MarkerID;
foreach (GridViewRow row in this.Rows)
{
CheckBox box = row.Cells[CheckBoxIndex].Controls[0] as CheckBox;
if (box != null)
{
string key = this.DataKeys[row.RowIndex].Value.ToString() + ";";
bool allSelect = AllSelect ?? false;
if (box.Checked != allSelect && !markids.Contains(key))
{
markids += key;
}
else if (box.Checked == allSelect && markids.Contains(key))
{
markids.Replace(key, "");
}
}
}
MarkerID = markids;
}
/// <summary>
/// 每次重新绑定时把相应的CheckBox赋上值
/// </summary>
private void UpdateGridViewSelect()
{
if (this.DataKeyNames.Length < 1)
throw new Exception("GridView没有设置DataKeyNames");
UpdateGridViewHeadSelect();
string markids = MarkerID;
foreach (GridViewRow row in this.Rows)
{
CheckBox box = row.Cells[CheckBoxIndex].Controls[0] as CheckBox;
if (box != null)
{
string key = this.DataKeys[row.RowIndex].Value.ToString() + ";";
bool bMarkid = markids.Contains(key);
bool allSelect = AllSelect ?? false;
box.Checked = bMarkid != allSelect;
}
}
}
/// <summary>
/// 更新GridView栏位上的CheckBox
/// </summary>
private void UpdateGridViewHeadSelect()
{
if (this.HeaderRow != null)
{
CheckBox box = this.HeaderRow.Cells[CheckBoxIndex].Controls[0] as CheckBox;
if (box != null)
box.Checked = AllSelect ?? false;
}
}
/// <summary>
/// 分页时调用修改的CheckBox值.
/// </summary>
/// <param name="e"></param>
protected override void OnPageIndexChanging(GridViewPageEventArgs e)
{
if (AddCheckBox)
CheckGridViewSelect();
base.OnPageIndexChanging(e);
}
/// <summary>
/// 分页完成后给CheckBox赋值
/// </summary>
/// <param name="e"></param>
protected override void OnPageIndexChanged(EventArgs e)
{
if (AddCheckBox)
UpdateGridViewSelect();
base.OnPageIndexChanged(e);
}
protected override void OnRowDataBound(GridViewRowEventArgs e)
{
if (AddCheckBox)
UpdateGridViewSelect();
base.OnDataBound(e);
} #endregion
#region 供后台得到选择了的主键信息,或检测主键是否选择了的对应函数
/// <summary>
/// 得到被标记的主键,如果是全选状态,刚是得到没被勾选的主键集,反之是得到被勾选的主键集
/// </summary>
/// <typeparam name="T">主键类型</typeparam>
/// <param name="bSelect">得到全选状态</param>
/// <returns></returns>
public List<T> GetSelectKey<T>(out bool bSelect)
{
CheckGridViewSelect();
bSelect = AllSelect ?? false;
string markids = MarkerID;
if (string.IsNullOrEmpty(markids))
return new List<T>();
markids = markids.TrimEnd(';');
return markids.Split(';').ToList()
.Select(p => StringConvertT<T>(p))
.ToList();
}
/// <summary>
/// 查找GridView里选择了的数据
/// </summary>
/// <typeparam name="T">数据源的每条数据类型</typeparam>
/// <param name="data">GridView的数据源</param>
/// <returns></returns>
public List<T> GetSelectData<T>(IEnumerable<T> data)
{
return GetSelectData<T>(data, true);
}
/// <summary>
/// 查找GridView里是否选择了的数据
/// </summary>
/// <typeparam name="T">数据源的每条数据类型</typeparam>
/// <param name="data">GridView的数据源</param>
/// <param name="IsSelect">true表示查找勾选上的,false表示查找没被勾选上的</param>
/// <returns></returns>
public List<T> GetSelectData<T>(IEnumerable<T> data, bool bSelect)
{
CheckGridViewSelect();
bool allSelect = AllSelect ?? false;
string markids = MarkerID;
PropertyInfo info = typeof(T).GetProperty(DataKeyNames[0]);
if (info == null)
throw new Exception("请确认数据源里有属性" + DataKeyNames[0] + ".");
var result = data.Where(p =>
{
var id = info.GetValue(p, null).ToString();
if (bSelect)
return allSelect != markids.Contains(id + ";");
else
return allSelect == markids.Contains(id + ";");
});
return result.ToList();
}
/// <summary>
/// 查看一行的主键是否被选中(要保证传入的key是在数据源里的,不然全选状态下可能会得到错误结果.)
/// </summary>
/// <param name="key">主键</param>
/// <returns>true-选中,false-没被选择</returns>
public bool IsSelect(object key)
{
CheckGridViewSelect();
bool allSelect = AllSelect ?? false;
return allSelect != MarkerID.Contains(key.ToString() + ";");
}
/// <summary>
/// 把string类数据转化成对应的T,支持基本数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
private T StringConvertT<T>(string data)
{
if (string.IsNullOrEmpty(data))
throw new NullReferenceException("主建不能用空.");
if (typeof(T) == typeof(Guid))
{
object id = new Guid(data);
return (T)id;
}
else if (typeof(T).IsAssignableFrom(typeof(IConvertible)))
{
object t = Convert.ChangeType(data, typeof(T));
return (T)t;
}
else
{
throw new Exception("不支持的类型.");
}
}
#endregion
#endregion
}
public class SelectDataField : DataControlField
{
private CheckBox box;
public SelectDataField()
{
box = new CheckBox();
}
protected override DataControlField CreateField()
{
return new SelectDataField();
}
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
base.InitializeCell(cell, cellType, rowState, rowIndex);
switch (cellType)
{
case DataControlCellType.Header:
{
box.CheckedChanged += new EventHandler(box_CheckedChanged);
box.Text = "选择";
box.TextAlign = TextAlign.Right;
box.AutoPostBack = true;
cell.HorizontalAlign = HorizontalAlign.Left;
cell.Controls.Add(box);
break;
}
case DataControlCellType.DataCell:
{
CheckBox checkbox = new CheckBox();
checkbox.AutoPostBack = false;
cell.Controls.Add(checkbox);
break;
}
default:
break;
}
}
public delegate void CheckboxChangedEventHandler(object sender, EventArgs e);
public event CheckboxChangedEventHandler CheckboxChanged;
void box_CheckedChanged(object sender, EventArgs e)
{
if (CheckboxChanged != null)
CheckboxChanged(sender, e);
}
}
这里还是说下怎么记录各个选择项的,就我使用全选操作后的条目.
1.没有点击全选,那么我用MarkerID记录所有选择了的主键.
2.点击全选后,那么我用MarkerID记录的是所有去掉选择了的主键. 每次点击全选,都用清空MarkerID.还有,TGridView一定要设置DataKeyNames. 下用是效果图.
从上面也可以看出, DataKeyNames.Length应该只能为1,就是说不设置或设置几个是有问题的,其实这个大家有兴趣,可以自己修改相关的一些代码.
<asp:TGridView ID="grvViewT" AutoGenerateColumns="false" CheckBoxIndex="2" runat="server" AllowPaging="true" OnPageIndexChanging="grvViewT_PageIndexChanging"
DataKeyNames="ID" >
<Columns>
<asp:BoundField DataField="A" HeaderText="A" />
<asp:BoundField DataField="B" HeaderText="B" />
<asp:BoundField DataField="C" HeaderText="C" />
<asp:BoundField DataField="D" HeaderText="D" />
</Columns>
</asp:TGridView>

相关资料:
http://www.cnblogs.com/yanyangtian/category/155681.html
还有相关Reflector的相关GridView的源码.