大家GridView都用的比较多吧..   有没遇到单元格需要合并的需求.. 

单元格合并原理其实很简单,就是逐行判断要合并的单元格里的值是否和上一行的相同,要是相同的话就合并,不同的话就接着判断

我们可以通过扩展方法为GridView添加单元合并

 

我为GridView 创建了个RowSpan的方法 .   有一个object 参数 

为什要定义object 参数  源于ASP.NET MVC 的Routing 组件配置规则  感觉这种方式很不错..

所以使用了这种方式来进行.

 

 

  1  public static class GridViewExtensions
  2     {
  3         /// <summary>
  4         ///  GridView行合并
  5         /// </summary>
  6         /// <param name="gridView"></param>
  7         /// <param name="field">合并参数(匿名类型)
  8         /// ColumnIndex:要合并行的索引 (以0开始,必须指定)
  9         /// ColumnControlID(可选):如果该行为模板行则必须指定 
 10         /// PropertyName:根据ID属性 默认值为Text
 11         /// Colums:(string类型)表示额外的行合并方式和ColumnIndex一样(多个使用逗号隔开,如Colums="5,6,7,8")
 12         /// 例:
 13         /// 合并第一行(第一行为模板行),绑定的一个Label名称为lblName  根据Text属性值合并  第6行方式和第一行相同
 14         /// new {ColumnIndex=0,ColumnControlID="lblName",PropertyName="Text",Columns="5"}
 15         /// </param>
 16         public static GridView RowSpan(this GridView gridView, object field)
 17         {
 18             Dictionary<stringstring> rowDictionary = ObjectLoadDictionary(field);
 19             int columnIndex = int.Parse(rowDictionary["ColumnIndex"]);
 20             string columnName = rowDictionary["ColumnControlID"];
 21             string propertyName = rowDictionary["PropertyName"];
 22             string columns = rowDictionary["Columns"];
 23             for (var i = 0; i < gridView.Rows.Count; i++)
 24             {
 25 
 26                 int rowSpanCount = 1;
 27                 for (int j = i + 1; j < gridView.Rows.Count; j++)
 28                 {
 29                     //绑定行合并处理
 30                     if (string.IsNullOrEmpty(columnName))
 31                     {
 32                         //比较2行的值是否相同
 33                         if (gridView.Rows[i].Cells[columnIndex].Text == gridView.Rows[j].Cells[columnIndex].Text)
 34                         {
 35                             //合并行的数量+1
 36                             rowSpanCount++;
 37                             //隐藏相同的行
 38                             gridView.Rows[j].Cells[columnIndex].Visible = false;
 39                             if (!string.IsNullOrEmpty(columns))
 40                             {
 41                                 columns.Split(',').ToList<string>().ForEach(c => gridView.Rows[j].Cells[int.Parse(c)].Visible=false);
 42                             }
 43                         }
 44                         else
 45                         {
 46                             break;
 47                         }
 48                     }
 49                     else
 50                     {
 51                         //模板行的合并处理
 52                         if (GetPropertyValue(gridView.Rows[i].Cells[columnIndex].FindControl(columnName), propertyName).ToString() == GetPropertyValue(gridView.Rows[j].Cells[columnIndex].FindControl(columnName), propertyName).ToString())
 53                         {
 54                             rowSpanCount++;
 55                             //隐藏相同的行
 56                             gridView.Rows[j].Cells[columnIndex].Visible = false;
 57                             if (!string.IsNullOrEmpty(columns))
 58                             {
 59                                 
 60                                 columns.Split(',').ToList<string>().ForEach(c => gridView.Rows[j].Cells[int.Parse(c)].Visible = false);
 61                             }
 62                         }
 63                         else
 64                         {
 65                             break;
 66                         }
 67                     }
 68                 }
 69                 if (rowSpanCount > 1)
 70                 {
 71                     //行合并
 72                     gridView.Rows[i].Cells[columnIndex].RowSpan = rowSpanCount;
 73                     //判断是否有额外的行需要合并
 74                     if (!string.IsNullOrEmpty(columns))
 75                     {
 76                         //额外的行合并
 77                         columns.Split(',').ToList<string>().ForEach(c => gridView.Rows[i].Cells[int.Parse(c)].RowSpan = rowSpanCount);
 78                     }
 79                     i = i + rowSpanCount - 1;
 80                 }
 81                 
 82 
 83             }
 84             return gridView;
 85         }
 86 
 87         private static Dictionary<stringstring> ObjectLoadDictionary(object fields)
 88         {
 89             Dictionary<stringstring> resultDictionary = new Dictionary<stringstring>();
 90             PropertyInfo[] property = fields.GetType().GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.GetProperty);
 91             foreach (PropertyInfo tempProperty in property)
 92             {
 93                 resultDictionary.Add(tempProperty.Name, tempProperty.GetValue(fields, null).ToString());
 94             }
 95             //指定默认值
 96             if (!resultDictionary.Keys.Contains("ColumnIndex"))
 97             {
 98                 throw new Exception("未指定要合并行的索引 ColumnIndex 属性!");
 99             }
100             if (!resultDictionary.Keys.Contains("ColumnControlID"))
101             {
102                 resultDictionary.Add("ColumnControlID"null);
103             }
104 
105             if (!resultDictionary.Keys.Contains("PropertyName"))
106             {
107                 resultDictionary.Add("PropertyName""Text");
108             }
109 
110             if (!resultDictionary.Keys.Contains("Columns"))
111             {
112                 resultDictionary.Add("Columns"null);
113             }
114             
115 
116            
117 
118             return resultDictionary;
119         }
120 
121         /// <summary>
122         ///  获取一个对象的一个属性..
123         /// </summary>
124         /// <param name="obj"></param>
125         /// <param name="PropertyName">属性名称</param>
126         /// <returns>属性的值,  如果无法获取则返回null</returns>
127         private static object GetPropertyValue(object obj, string PropertyName)
128         {
129             PropertyInfo property = obj.GetType().GetProperty(PropertyName);
130             return property.GetValue(obj,null);
131         }
132     }

这个扩展方法的使用方式很简单

 

 var s = new[] { 
                
new { 姓名 = "张三", 性别 = "", 语文 = 86f, 数学 = 90f, 学期 = "第一学期" },  
                
new { 姓名 = "张三", 性别 = "", 语文 = 89f, 数学 = 98f, 学期 = "第二学期" }, 
                
new { 姓名 = "李四", 性别 = "", 语文 = 89f, 数学 = 64f, 学期 = "第一学期" },  
                
new { 姓名 = "李四", 性别 = "", 语文 = 75f, 数学 = 64f, 学期 = "第二学期" },
                
new { 姓名 = "王五", 性别 = "", 语文 = 89f, 数学 = 64f, 学期 = "第一学期" },  
                
new { 姓名 = "王五", 性别 = "", 语文 = 63f, 数学 = 93f, 学期 = "第二学期" }
            };
            
this.GridView1.DataSource = s;
            
this.GridView1.DataBind();
            
this.GridView1.RowSpan(new { ColumnIndex = 0, Columns = "1" }); 

我们合并第1列的值姓名..  GirdView索引是从0开始的所以ColumnIndex=0 性别肯定和姓名对应的

可以是用Colunmns="" 这个属性来指定哪个列的合并方式和 ColumnIndex指定的列相同  多个用 ","隔开比如 Colunmns="2,3,4,5"这种方式

如果GridView中使用了模板列 则除了需要指定ColumnIndex外还需要添加ID和PropertyName属性

如 new {ColumnIndex=0,ID="lblName",PropertyName="Text",Columns="1" }

 ID 表示模板列的控件名称 PropertyName 表示值来自于控件的哪个属性.  

注:暂时只能指定普通属性如Text 或Value ;SelectedItem.Value 这种属性需要修改部分代码  也不能包含容器控件 修改部分代码可以支持容器控件

效果图

姓名 性别 语文 数学 学期
张三 86 90 第一学期
89 98 第二学期
李四 89 64 第一学期
75 64 第二学期
王五 89 64 第一学期
63 93 第二学期

 

合并姓名和语文相同的分数

 

   var s = new[] { 
                
new { 姓名 = "张三", 性别 = "", 语文 = 86f, 数学 = 90f, 学期 = "第一学期" },  
                
new { 姓名 = "张三", 性别 = "", 语文 = 89f, 数学 = 98f, 学期 = "第二学期" }, 
                
new { 姓名 = "李四", 性别 = "", 语文 = 89f, 数学 = 64f, 学期 = "第一学期" },  
                
new { 姓名 = "李四", 性别 = "", 语文 = 75f, 数学 = 64f, 学期 = "第二学期" },
                
new { 姓名 = "王五", 性别 = "", 语文 = 89f, 数学 = 64f, 学期 = "第一学期" },  
                
new { 姓名 = "王五", 性别 = "", 语文 = 63f, 数学 = 93f, 学期 = "第二学期" }
            };
            
this.GridView1.DataSource = s;
            
this.GridView1.DataBind();
            
this.GridView1.RowSpan(new { ColumnIndex = 0, Columns = "1" });
            
this.GridView1.RowSpan(new { ColumnIndex = 2 });

 

姓名 性别 语文 数学 学期
张三 86 90 第一学期
89 98 第二学期
李四 64 第一学期
75 64 第二学期
王五 89 64 第一学期
63 93 第二学期

可以使用这种方式

 this.GridView1.RowSpan(new { ColumnIndex = 0, Columns = "1" }).RowSpan(new { ColumnIndex = 2 }).RowSpan(new { ColumnIndex = 3 });

 

姓名 性别 语文 数学 学期
张三 86 90 第一学期
89 98 第二学期
李四 64 第一学期
75 第二学期
王五 89 第一学期
63 93 第二学期

 

 

 

还有什么额外的参数配置 大家可以提出来 我进行改进.  

 效率问题 我可以考虑使用Lambda表达式树动态创建Lambda表达式的效率

Lambda表达式调用的效率差别可以看

老赵的方法的直接调用,反射调用与……Lambda表达式调用这篇文章

 
posted on 2010-08-10 18:22  程序诗人  阅读(1519)  评论(1编辑  收藏  举报