大家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
<
string
,
string
>
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
<
string
,
string
>
ObjectLoadDictionary(
object
fields)
88
{
89
Dictionary
<
string
,
string
>
resultDictionary
=
new
Dictionary
<
string
,
string
>
();
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表达式调用这篇文章