博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

扩展GridView控件--增加选择列

Posted on 2008-12-10 23:33  codingsilence  阅读(458)  评论(0编辑  收藏  举报
 

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