(一). 概要
开发 <数据绑定用户控件> , 要实现一个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 /// 7 /// Author: [ ChengKing(ZhengJian) ] 8 /// Blog: Http://blog.csdn.net/ChengKing 9 /// 10 public partial class LinkList : System.Web.UI.UserControl 11 { 12 13 private bool blnMultiTypeDataSource = false ; 14 15 #region 属性 16 17 18 19 /// 20 /// 表格每行图像控件的指向图片名称 21 /// 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 /// 42 /// 表格每行链接控件显示的文本 43 /// 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 /// 64 /// 表格第行链接控件的跳转目标页面链接 65 /// 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 /// 86 /// 表格每行的链接目标页面打开方式 87 /// 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 /// 319 /// 当设置数据源时, 要验证XML文件格式是否正确; 当格式不正确时,此方法用来处理当XML文件格式不正确时,要进行的操作320 /// 321 /// 322 /// 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 /// 2 /// Author: [ ChengKing(ZhengJian) ] 3 /// Blog: Http://blog.csdn.net/ChengKing 4 /// 5 public partial class _Default : System.Web.UI.Page 6 { 7 protected void Page_Load( object sender, EventArgs e) 8 { 9 /// 10 /// 测试通过各种数据源进行绑定11 /// 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