随笔 - 394  文章 - 0  评论 - 946  阅读 - 143万 

大家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   程序诗人  阅读(1520)  评论(1编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示