(一). 概要
开发<数据绑定用户控件>, 要实现一个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. 用户控件部分
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. 使用不同数据源绑定
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 }