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