(一). 概要
开发<数据绑定用户控件>, 要实现一个DataSource属性, 并且能够自动识别不同的数据源, 如: ArrayList,
DataTable, DataSet, XML文件等.
在书上和网上找了些资料, 它们一般的实现方案是把一些具有DataSource属性的数据控件
DataList/Reapter等嵌套到用户控件里面实现, 比较容易实现. 但也存在一些问题:
1. 如果实现很简单的功能, 把一个DataList嵌套在用户控件里面, 有些大才小用, 比较庞大, 产生冗余代码较
多, 效率也不会很高.
2. 缺乏灵活性. 由于嵌套数据绑定控件到用户控件中, 毕竟是"变态"地做法; 这样太依赖现在数据绑定控件,
实现某些特殊功能缺乏灵活性, 甚至有些功能受限制而无法实现.
决定自己写一个. 在用户控件中实现数据源DataSource属性比自定义控件中复杂多了. 自定义控件中, 尤
其是在 Dot Net 2.0中实现此属性非常简单, 具体是实现 BaseDataBoundControl(数据绑定基类)/
/DataBoundControl(列表和表格控件基类)和HierarchicalDataBoundControl(开发Tree和Menu基类)等几个
基类, 再重写几个方法就OK了.
但用户控件遇到麻烦, 它默认已经继承了 System.Web.UI.UserControl 用户控件基类, 不能再继承其它
类了(C#语法规定不允许多继承). 下面这个例子是参考了一个本上的一个自定义控件例子, 修改了一些代码,
把它改到这个用户控件中了. 网上很难找到用户控件这样的示例, 共享一下.
控件很简单, 只有DataSource相关的几个属性
[涉及到公司代码版权问题, 自己单独做了个只有DataSource功能的最简单例子, 文章主旨只讲这个属性] .
(二). 绑定效果
(三). 核心代码
1. 用户控件部分
1
using
System.ComponentModel;
2
using
System.Xml;
3
using
System.Xml.Schema;
4
using
System.Xml.Serialization;
5
6
///
<summary>
7
///
Author: [ ChengKing(ZhengJian) ]
8
///
Blog: Http://blog.csdn.net/ChengKing
9
///
</summary>
10
public
partial
class
LinkList : System.Web.UI.UserControl
11
{
12
13
private
bool
blnMultiTypeDataSource
=
false
;
14
15
#region
属性
16
17
18
19
///
<summary>
20
///
表格每行图像控件的指向图片名称
21
///
</summary>
22
[
23
Bindable(
true
),
24
Category(
"
Data
"
),
25
DefaultValue(
null
)
26
]
27
public
string
DataImageField
28
{
29
get
30
{
31
String s
=
(String)ViewState[
"
DataImageField
"
];
32
return
((s
==
null
)
?
String.Empty : s);
33
}
34
35
set
36
{
37
ViewState[
"
DataImageField
"
]
=
value;
38
}
39
}
40
41
///
<summary>
42
///
表格每行链接控件显示的文本
43
///
</summary>
44
[
45
Bindable(
true
),
46
Category(
"
Data
"
),
47
DefaultValue(
null
)
48
]
49
public
string
DataTextField
50
{
51
get
52
{
53
String s
=
(String)ViewState[
"
DataTextField
"
];
54
return
((s
==
null
)
?
String.Empty : s);
55
}
56
57
set
58
{
59
ViewState[
"
DataTextField
"
]
=
value;
60
}
61
}
62
63
///
<summary>
64
///
表格第行链接控件的跳转目标页面链接
65
///
</summary>
66
[
67
Bindable(
true
),
68
Category(
"
Data
"
),
69
DefaultValue(
null
)
70
]
71
public
string
DataLinkToField
72
{
73
get
74
{
75
String s
=
(String)ViewState[
"
DataLinkToField
"
];
76
return
((s
==
null
)
?
String.Empty : s);
77
}
78
79
set
80
{
81
ViewState[
"
DataLinkToField
"
]
=
value;
82
}
83
}
84
85
///
<summary>
86
///
表格每行的链接目标页面打开方式
87
///
</summary>
88
[
89
Bindable(
true
),
90
Category(
"
Data
"
),
91
DefaultValue(
null
)
92
]
93
public
string
DataLinkTargetField
94
{
95
get
96
{
97
String s
=
(String)ViewState[
"
DataLinkTargetField
"
];
98
return
((s
==
null
)
?
String.Empty : s);
99
}
100
101
set
102
{
103
ViewState[
"
DataLinkTargetField
"
]
=
value;
104
}
105
}
106
107
private
object
_dataSource;
108
109
[
110
Bindable(
true
),
111
Category(
"
Data
"
),
112
DefaultValue(
null
),
113
Description(
"
获取或设置数据源
"
),
114
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
115
]
116
public
virtual
object
DataSource
117
{
118
get
119
{
120
return
_dataSource;
121
}
122
set
123
{
124
if
((value
==
null
)
||
(value
is
IListSource)
||
(value
is
IEnumerable))
125
{
126
_dataSource
=
value;
127
}
128
else
129
{
130
throw
new
ArgumentException();
131
}
132
}
133
}
134
135
[
136
Category(
"
Data
"
),
137
DefaultValue(
""
),
138
Description(
"
获取或者设置绑定的数据成员.
"
)
139
]
140
public
virtual
string
DataMember
141
{
142
get
143
{
144
string
s
=
(
string
)ViewState[
"
DataMember
"
];
145
return
(s
==
null
)
?
String.Empty : s;
146
}
147
set
148
{
149
ViewState[
"
DataMember
"
]
=
value;
150
}
151
}
152
153
[
154
Bindable(
true
),
155
Category(
"
Data
"
),
156
DefaultValue(
null
),
157
Description(
"
获取或设置XML文件路径
"
),
158
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
159
]
160
public
virtual
string
XMLDataFile
161
{
162
get
163
{
164
string
s
=
(
string
)ViewState[
"
XMLDataFile
"
];
165
return
(s
==
null
)
?
String.Empty : s;
166
}
167
set
168
{
169
ViewState[
"
XMLDataFile
"
]
=
value;
170
}
171
}
172
173
[
174
Bindable(
true
),
175
Category(
"
Data
"
),
176
DefaultValue(
null
),
177
Description(
"
获取或设置XML模式文件路径
"
),
178
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
179
]
180
public
virtual
string
XMLSchemaFile
181
{
182
get
183
{
184
string
s
=
(
string
)ViewState[
"
XMLSchemaFile
"
];
185
return
(s
==
null
)
?
String.Empty : s;
186
}
187
set
188
{
189
ViewState[
"
XMLSchemaFile
"
]
=
value;
190
}
191
}
192
193
#endregion
194
195
protected
override
void
CreateChildControls()
196
{
197
Controls.Clear();
198
CreateControlHierarchy();
199
base
.CreateChildControls();
200
}
201
202
protected
virtual
void
CreateControlHierarchy()
203
{
204
Table tbParent
=
new
Table();
205
tbParent.Attributes.Add(
"
Cellpadding
"
,
"
0
"
);
206
tbParent.Attributes.Add(
"
Cellspacing
"
,
"
0
"
);
207
208
IEnumerable dataSource
=
null
;
209
int
rowCount
=
0
;
210
int
columnCount
=
0
;
211
dataSource
=
GetDataSource();
212
213
if
(dataSource
!=
null
)
214
{
215
PropertyDescriptor[] properties
=
null
;
216
foreach
(
object
dataItem
in
dataSource)
217
{
218
properties
=
GetColumnPropertyDescriptors(dataItem);
219
columnCount
=
properties.Length;
220
221
for
(
int
i
=
0
; i
<
(columnCount
-
3
); i
++
)
222
{
223
if
(blnMultiTypeDataSource
==
false
)
224
{
225
PropertyDescriptor pdImage
=
properties[i];
226
object
cellImage
=
pdImage.GetValue(dataItem);
227
string
imageSrc
=
(
string
)pdImage.Converter.ConvertTo(cellImage,
typeof
(
string
));
228
229
PropertyDescriptor pdText
=
properties[i
+
2
];
230
object
cellText
=
pdText.GetValue(dataItem);
231
string
text
=
(
string
)pdText.Converter.ConvertTo(cellText,
typeof
(
string
));
232
233
PropertyDescriptor pdLinkTo
=
properties[i
+
3
];
234
object
cellLinkTo
=
pdLinkTo.GetValue(dataItem);
235
string
linkTo
=
(
string
)pdLinkTo.Converter.ConvertTo(cellLinkTo,
typeof
(
string
));
236
237
PropertyDescriptor pdLinkTarget
=
properties[i
+
1
];
238
object
cellLinkTarget
=
pdLinkTarget.GetValue(dataItem);
239
string
linkTarget
=
(
string
)pdLinkTarget.Converter.ConvertTo(cellLinkTarget,
typeof
(
string
));
240
241
ItemRow item
=
new
ItemRow(imageSrc, text, linkTo, linkTarget);
242
243
tbParent.Controls.Add(item);
244
}
245
else
246
{
247
string
imageSrc
=
""
;
248
string
text
=
""
;
249
string
linkTo
=
""
;
250
string
linkTarget
=
""
;
251
for
(
int
j
=
0
; j
<
columnCount; j
++
)
252
{
253
PropertyDescriptor pd
=
properties[j];
254
object
objValue
=
pd.GetValue(dataItem);
255
string
strValue
=
(
string
)pd.Converter.ConvertTo(objValue,
typeof
(
string
));
256
if
(String.Compare(pd.Name,
this
.DataImageField,
true
)
==
0
)
257
{
258
imageSrc
=
strValue;
259
}
260
if
(String.Compare(pd.Name,
this
.DataTextField,
true
)
==
0
)
261
{
262
text
=
strValue;
263
}
264
if
(String.Compare(pd.Name,
this
.DataLinkToField,
true
)
==
0
)
265
{
266
linkTo
=
strValue;
267
}
268
if
(String.Compare(pd.Name,
this
.DataLinkTargetField,
true
)
==
0
)
269
{
270
linkTarget
=
strValue;
271
}
272
}
273
ItemRow item
=
new
ItemRow(imageSrc, text, linkTo, linkTarget);
274
tbParent.Controls.Add(item);
275
}
276
}
277
278
this
.Controls.Add(tbParent);
279
rowCount
++
;
280
}
281
}
282
283
if
(
this
.XMLDataFile
+
String.Empty
!=
String.Empty)
284
{
285
XmlReaderSettings settings
=
new
XmlReaderSettings();
286
settings.IgnoreWhitespace
=
true
;
287
settings.IgnoreComments
=
true
;
288
NameTable nt
=
new
NameTable();
289
string
link
=
nt.Add(
"
link
"
);
290
settings.NameTable
=
nt;
291
292
//
验证
293
settings.Schemas.Add(
null
, XmlReader.Create(
this
.XMLSchemaFile));
294
settings.ValidationType
=
ValidationType.Schema;
295
settings.ValidationFlags
=
XmlSchemaValidationFlags.ReportValidationWarnings;
296
settings.ValidationEventHandler
+=
new
ValidationEventHandler(settings_ValidationEventHandler);
297
298
//
序列化工厂类
299
XmlSerializerFactory factory
=
new
XmlSerializerFactory();
300
301
using
(XmlReader reader
=
XmlReader.Create(
this
.XMLDataFile, settings))
302
{
303
while
(reader.Read())
304
{
305
if
(reader.NodeType
==
XmlNodeType.Element
&&
String.Compare(link, reader.LocalName,
true
)
==
0
)
306
{
307
XmlSerializer xs
=
factory.CreateSerializer(
typeof
(Link));
308
Link l
=
(Link)xs.Deserialize(reader.ReadSubtree());
309
ItemRow item
=
new
ItemRow(l.ImageName, l.Text, l.LinkTo, l.LinkTarget);
310
tbParent.Rows.Add(item);
311
}
312
}
313
}
314
this
.Controls.Add(tbParent);
315
}
316
}
317
318
///
<summary>
319
///
当设置数据源时, 要验证XML文件格式是否正确; 当格式不正确时,此方法用来处理当XML文件格式不正确时,要进行的操作
320
///
</summary>
321
///
<param name="sender"></param>
322
///
<param name="e"></param>
323
private
void
settings_ValidationEventHandler(
object
sender, System.Xml.Schema.ValidationEventArgs e)
324
{
325
throw
new
Exception(
"
数据文件:
"
+
this
.XMLDataFile
+
"
格式不正确! [
"
+
e.Message
+
"
]
"
);
326
}
327
328
protected
override
void
Render(HtmlTextWriter writer)
329
{
330
base
.Render(writer);
331
}
332
333
public
override
void
DataBind()
334
{
335
base
.OnDataBinding(EventArgs.Empty);
336
Controls.Clear();
337
ClearChildViewState();
338
TrackViewState();
339
CreateControlHierarchy();
340
ChildControlsCreated
=
true
;
341
}
342
343
private
PropertyDescriptor[] GetColumnPropertyDescriptors(
object
dataItem)
344
{
345
ArrayList props
=
new
ArrayList();
346
PropertyDescriptorCollection propDescs
=
TypeDescriptor.GetProperties(dataItem);
347
foreach
(PropertyDescriptor pd
in
propDescs)
348
{
349
Type propType
=
pd.PropertyType;
350
TypeConverter converter
=
TypeDescriptor.GetConverter(propType);
351
if
((converter
!=
null
)
&&
converter.CanConvertTo(
typeof
(
string
)))
352
{
353
props.Add(pd);
354
}
355
}
356
PropertyDescriptor[] columns
=
new
PropertyDescriptor[props.Count];
357
props.CopyTo(columns,
0
);
358
return
columns;
359
}
360
361
362
//
获取数据源,将数据源中的数据都转换为IEnumerable类型
363
protected
virtual
IEnumerable GetDataSource()
364
{
365
if
(_dataSource
==
null
)
366
{
367
return
null
;
368
}
369
IEnumerable resolvedDataSource
=
_dataSource
as
IEnumerable;
370
if
(resolvedDataSource
!=
null
)
371
{
372
return
resolvedDataSource;
//
强类型集合类型/ArrayList
373
}
374
375
this
.blnMultiTypeDataSource
=
true
;
376
377
IListSource listSource
=
_dataSource
as
IListSource;
378
if
(listSource
!=
null
)
379
{
380
IList memberList
=
listSource.GetList();
381
382
if
(listSource.ContainsListCollection
==
false
)
383
{
384
return
(IEnumerable)memberList;
//
DataTable
385
}
386
ITypedList typedMemberList
=
memberList
as
ITypedList;
387
if
(typedMemberList
!=
null
)
388
{
389
PropertyDescriptorCollection propDescs
=
typedMemberList.GetItemProperties(
new
PropertyDescriptor[
0
]);
390
PropertyDescriptor memberProperty
=
null
;
391
392
if
((propDescs
!=
null
)
&&
(propDescs.Count
!=
0
))
393
{
394
string
dataMember
=
DataMember;
395
396
if
(dataMember.Length
==
0
)
397
{
398
memberProperty
=
propDescs[
0
];
399
}
400
else
401
{
402
memberProperty
=
propDescs.Find(dataMember,
true
);
403
}
404
405
if
(memberProperty
!=
null
)
406
{
407
object
listRow
=
memberList[
0
];
408
object
list
=
memberProperty.GetValue(listRow);
409
410
if
(list
is
IEnumerable)
411
{
412
return
(IEnumerable)list;
//
DataSet
413
}
414
}
415
throw
new
Exception(
"
未能找到有效的DataMember.
"
);
416
}
417
418
throw
new
Exception(
"
数据源中不包含任何数据对象.
"
);
419
}
420
}
421
return
null
;
422
}
423
}
2. 使用不同数据源绑定
1
///
<summary>
2
///
Author: [ ChengKing(ZhengJian) ]
3
///
Blog: Http://blog.csdn.net/ChengKing
4
///
</summary>
5
public
partial
class
_Default : System.Web.UI.Page
6
{
7
protected
void
Page_Load(
object
sender, EventArgs e)
8
{
9
///
<summary>
10
///
测试通过各种数据源进行绑定
11
///
</summary>
12
13
//
(一). 绑定强类型集合类型
14
ItemList itemList
=
new
ItemList();
15
itemList.Add(
new
Item(
@"
Images\img.gif
"
,
"
宁波宇泰软件股份有限公司
"
,
"
http://www.xframe.com.cn
"
,
"
blank
"
));
16
itemList.Add(
new
Item(
@"
Images\img.gif
"
,
"
宁波宇泰软件开发有限公司
"
,
"
http://www.xframe.com.cn
"
,
"
blank
"
));
17
DataSourceInUserControl1.DataSource
=
itemList;
18
DataSourceInUserControl1.DataBind();
19
20
//
(二). 绑定ArraList集合类型
21
ArrayList al
=
new
ArrayList();
22
al.Add(
new
Item(
@"
Images\img.gif
"
,
"
宁波宇泰软件股份有限公司
"
,
"
http://www.xframe.com.cn
"
,
"
blank
"
));
23
al.Add(
new
Item(
@"
Images\img.gif
"
,
"
宁波宇泰软件开发有限公司
"
,
"
http://www.xframe.com.cn
"
,
"
blank
"
));
24
DataSourceInUserControl1.DataSource
=
al;
25
DataSourceInUserControl1.DataBind();
26
27
//
(三). 测试绑定DataTable
28
DataTable dt
=
new
CusDataSource().CreateDataTable();
29
DataSourceInUserControl1.DataSource
=
dt;
30
DataSourceInUserControl1.DataImageField
=
"
ImageName
"
;
31
DataSourceInUserControl1.DataTextField
=
"
Text
"
;
32
DataSourceInUserControl1.DataLinkToField
=
"
LinkTo
"
;
33
DataSourceInUserControl1.DataLinkTargetField
=
"
LinkTarget
"
;
34
DataSourceInUserControl1.DataBind();
35
36
//
(四). 测试绑定DataSet
37
DataSet ds
=
new
CusDataSource().CreateDataSet();
38
DataSourceInUserControl1.DataSource
=
ds;
39
DataSourceInUserControl1.DataMember
=
ds.Tables[
0
].TableName;
//
如果不声明此句,会默认取DataSet中的第一个表
40
DataSourceInUserControl1.DataImageField
=
"
ImageName
"
;
41
DataSourceInUserControl1.DataTextField
=
"
Text
"
;
42
DataSourceInUserControl1.DataLinkToField
=
"
LinkTo
"
;
43
DataSourceInUserControl1.DataLinkTargetField
=
"
LinkTarget
"
;
44
DataSourceInUserControl1.DataBind();
45
46
///
/(五). 测试绑定XML
47
string
strDataFile
=
Path.Combine(Request.PhysicalApplicationPath,
"
LinkList.xml
"
);
48
string
strSchemaFile
=
Path.Combine(Request.PhysicalApplicationPath,
"
LinkList.xsd
"
);
49
DataSourceInUserControl1.XMLDataFile
=
strDataFile;
50
DataSourceInUserControl1.XMLSchemaFile
=
strSchemaFile;
51
}
52
}
(四). 示例代码下载
(五). 更多自定义控件开发相关文章
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1610497