GridView分页可以全选的改造
记上次有个项目,有几个都要求在GridView里可以进行对应的多选操作.本来这问题没什么难度,加上要求分页后就有点烦人了,因时间紧,想的最简单的方法就是用Session保存每页选择结果,现项目告一段落,静下来想了下,扩展GridView可以全选操作,用ViewState来保存(?不是吧,用ViewState,你不怕整个机器都读一个页面死机啊)所以这边会保证ViewState肯定记录没有很多内容.先看代码,比较简单.
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>
![](https://images.cnblogs.com/cnblogs_com/zhouxin/TGridView.jpg)
相关资料:
http://www.cnblogs.com/yanyangtian/category/155681.html
还有相关Reflector的相关GridView的源码.