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>

相关资料:

http://www.cnblogs.com/yanyangtian/category/155681.html

还有相关Reflector的相关GridView的源码.

posted @ 2011-03-10 15:47  天天不在  阅读(1487)  评论(0编辑  收藏  举报