2004-06-09 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / Repeater.cs
1 //
2 // System.Web.UI.WebControls.Repeater.cs
3 //
4 // Authors:
5 //   Gaurav Vaish (gvaish@iitk.ac.in)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //
9 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
10 // (C) Gaurav Vaish (2002)
11 // (C) 2003 Andreas Nahr
12 //
13 \r
14 using System;\r
15 using System.Collections;\r
16 using System.Web;\r
17 using System.Web.UI;\r
18 using System.Web.Util;\r
19 using System.ComponentModel;
20 using System.ComponentModel.Design;\r
21 \r
22 namespace System.Web.UI.WebControls\r
23 {\r
24         [DefaultEvent("ItemCommand")]\r
25         [DefaultProperty("DataSource")]\r
26         [Designer ("System.Web.UI.Design.WebControls.RepeaterDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]\r
27         [ParseChildren(true)]\r
28         [PersistChildren(false)]\r
29         public class Repeater : Control, INamingContainer\r
30         {\r
31                 private static readonly object ItemCommandEvent   = new object();\r
32                 private static readonly object ItemCreatedEvent   = new object();\r
33                 private static readonly object ItemDataBoundEvent = new object();\r
34 \r
35                 private static readonly string ITEMCOUNT = "Repeater_Item_Count";\r
36 \r
37                 private ITemplate alternatingItemTemplate;\r
38                 private ITemplate footerTemplate;\r
39                 private ITemplate headerTemplate;\r
40                 private ITemplate itemTemplate;\r
41                 private ITemplate separatorTemplate;\r
42                 private object    dataSource;\r
43 \r
44                 private RepeaterItemCollection items;\r
45                 private ArrayList              itemsArrayList;\r
46 \r
47                 public Repeater(): base()\r
48                 {\r
49                 }\r
50
51                 [WebCategory ("Action")]
52                 [WebSysDescription ("Raised when a command is executed in the DataList.")]\r
53                 public event RepeaterCommandEventHandler ItemCommand\r
54                 {\r
55                         add\r
56                         {\r
57                                 Events.AddHandler(ItemCommandEvent, value);\r
58                         }\r
59                         remove\r
60                         {\r
61                                 Events.RemoveHandler(ItemCommandEvent, value);\r
62                         }\r
63                 }\r
64
65                 [WebCategory ("Behavior")]
66                 [WebSysDescription ("Raised when an item gets created.")]\r
67                 public event RepeaterItemEventHandler ItemCreated\r
68                 {\r
69                         add\r
70                         {\r
71                                 Events.AddHandler(ItemCreatedEvent, value);\r
72                         }\r
73                         remove\r
74                         {\r
75                                 Events.RemoveHandler(ItemCreatedEvent, value);\r
76                         }\r
77                 }\r
78
79                 [WebCategory ("Behavior")]
80                 [WebSysDescription ("Raised when an item gets data-bound.")]\r
81                 public event RepeaterItemEventHandler ItemDataBound\r
82                 {\r
83                         add\r
84                         {\r
85                                 Events.AddHandler(ItemDataBoundEvent, value);\r
86                         }\r
87                         remove\r
88                         {\r
89                                 Events.RemoveHandler(ItemDataBoundEvent, value);\r
90                         }\r
91                 }\r
92
93                 [DefaultValue (null), Browsable (false), PersistenceMode (PersistenceMode.InnerProperty)]
94                 [TemplateContainer (typeof (RepeaterItem))]
95                 [WebSysDescription ("The template that is used to create an alternating item.")]\r
96                 public virtual ITemplate AlternatingItemTemplate\r
97                 {\r
98                         get\r
99                         {\r
100                                 return alternatingItemTemplate;\r
101                         }\r
102                         set\r
103                         {\r
104                                 alternatingItemTemplate = value;\r
105                         }\r
106                 }\r
107 \r
108                 public override ControlCollection Controls\r
109                 {\r
110                         get\r
111                         {\r
112                                 EnsureChildControls();\r
113                                 return base.Controls;\r
114                         }\r
115                 }\r
116
117                 [DefaultValue (""), WebCategory ("Data")]
118                 [WebSysDescription ("The name of the table that is used for binding when a DataSource is specified.")]\r
119                 public virtual string DataMember\r
120                 {\r
121                         get\r
122                         {\r
123                                 object o = ViewState["DataMember"];\r
124                                 if(o != null)\r
125                                 {\r
126                                         return (string)o;\r
127                                 }\r
128                                 return String.Empty;\r
129                         }\r
130                         set\r
131                         {\r
132                                 ViewState["DataMember"] = value;\r
133                         }\r
134                 }\r
135
136                 [DefaultValue (null), Bindable (true), WebCategory ("Data")]
137                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
138                 [WebSysDescription ("The DataSource that is used for data-binding.")]\r
139                 public virtual object DataSource\r
140                 {\r
141                         get\r
142                         {\r
143                                 return dataSource;\r
144                         }\r
145                         set\r
146                         {
147                                 if ((value!=null) && !(value is IListSource) && !(value is IEnumerable))
148                                         throw new ArgumentException ("An invalid data source is being used for " +
149                                                 ID + ". A valid data source must implement either " +
150                                                 "IListSource or IEnumerable.");
151                                 
152                                 dataSource = value;\r
153                         }\r
154                 }\r
155
156                 [DefaultValue (null), Browsable (false), PersistenceMode (PersistenceMode.InnerProperty)]
157                 [TemplateContainer (typeof (RepeaterItem))]
158                 [WebSysDescription ("The template that is used to create a footer.")]\r
159                 public virtual ITemplate FooterTemplate\r
160                 {\r
161                         get\r
162                         {\r
163                                 return footerTemplate;\r
164                         }\r
165                         set\r
166                         {\r
167                                 footerTemplate = value;\r
168                         }\r
169                 }\r
170
171                 [DefaultValue (null), Browsable (false), PersistenceMode (PersistenceMode.InnerProperty)]
172                 [TemplateContainer (typeof (RepeaterItem))]
173                 [WebSysDescription ("The template that is used to create a header.")]\r
174                 public virtual ITemplate HeaderTemplate\r
175                 {\r
176                         get\r
177                         {\r
178                                 return headerTemplate;\r
179                         }\r
180                         set\r
181                         {\r
182                                 headerTemplate = value;\r
183                         }\r
184                 }\r
185
186                 [Browsable (false)]
187                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
188                 [WebSysDescription ("A collection containing all items.")]\r
189                 public virtual RepeaterItemCollection Items\r
190                 {\r
191                         get\r
192                         {\r
193                                 if(items == null)\r
194                                 {\r
195                                         if(itemsArrayList == null)\r
196                                         {\r
197                                                 EnsureChildControls();\r
198                                         }\r
199                                         items = new RepeaterItemCollection(itemsArrayList);\r
200                                 }\r
201                                 return items;\r
202                         }\r
203                 }\r
204
205                 [DefaultValue (null), Browsable (false), PersistenceMode (PersistenceMode.InnerProperty)]
206                 [TemplateContainer (typeof (RepeaterItem))]
207                 [WebSysDescription ("The template that is used to create an item.")]\r
208                 public virtual ITemplate ItemTemplate\r
209                 {\r
210                         get\r
211                         {\r
212                                 return itemTemplate;\r
213                         }\r
214                         set\r
215                         {\r
216                                 itemTemplate = value;\r
217                         }\r
218                 }\r
219
220                 [DefaultValue (null), Browsable (false), PersistenceMode (PersistenceMode.InnerProperty)]
221                 [TemplateContainer (typeof (RepeaterItem))]
222                 [WebSysDescription ("The template that is used to create a seperator.")]\r
223                 public virtual ITemplate SeparatorTemplate\r
224                 {\r
225                         get\r
226                         {\r
227                                 return separatorTemplate;\r
228                         }\r
229                         set\r
230                         {\r
231                                 separatorTemplate = value;\r
232                         }\r
233                 }\r
234
235                 public override void DataBind ()
236                 {
237                         #if NET_2_0
238                         RequiresDataBinding = false;
239                         #endif
240                         OnDataBinding (EventArgs.Empty);
241                 }
242
243                 protected override void CreateChildControls()
244                 {
245                         Controls.Clear ();
246                         if (ViewState[ITEMCOUNT] != null) {
247                                 CreateControlHierarchy (false);
248                         } else {
249                                 itemsArrayList = new ArrayList ();
250                                 ClearChildViewState ();
251                         }
252                 }
253
254                 private RepeaterItem CreateItem (int itemIndex,\r
255                                                  ListItemType itemType,\r
256                                                  bool dataBind,\r
257                                                  object dataItem)\r
258                 {\r
259                         RepeaterItem repeaterItem = new RepeaterItem (itemIndex, itemType);\r
260                         RepeaterItemEventArgs repeaterEventArgs = new RepeaterItemEventArgs (repeaterItem);\r
261                         InstantiateItem (repeaterItem);\r
262                         if (dataBind)\r
263                                 repeaterItem.DataItem = dataItem;\r
264                         OnItemCreated (repeaterEventArgs);\r
265                         Controls.Add (repeaterItem);\r
266                         if (dataBind) {\r
267                                 repeaterItem.DataBind ();\r
268                                 OnItemDataBound (repeaterEventArgs);\r
269                                 repeaterItem.DataItem = null;\r
270                         }\r
271                         return repeaterItem;\r
272                 }\r
273 \r
274                 private void InstantiateItem (RepeaterItem item)\r
275                 {\r
276                         ITemplate template;\r
277                         switch (item.ItemType) {\r
278                                 case ListItemType.Header:\r
279                                         template = this.headerTemplate;\r
280                                         break;\r
281                                 case ListItemType.Footer:\r
282                                         template = this.footerTemplate;\r
283                                         break;\r
284                                 case ListItemType.Item:\r
285                                         template = this.itemTemplate;\r
286                                         break;\r
287                                 case ListItemType.AlternatingItem:\r
288                                         template = (alternatingItemTemplate != null ? this.alternatingItemTemplate : itemTemplate);\r
289                                         break;\r
290                                 case ListItemType.Separator:\r
291                                         template = this.separatorTemplate;\r
292                                         break;\r
293                                 default:\r
294                                         throw new HttpException ("Unknown ListItemType: " + item.ItemType);\r
295                         }\r
296 \r
297                         if (template != null)\r
298                                 template.InstantiateIn (item);\r
299                 }\r
300
301                 protected virtual void CreateControlHierarchy (bool useDataSource)
302                 {
303                         if (itemsArrayList != null) {
304                                 itemsArrayList.Clear ();
305                         } else {
306                                 itemsArrayList = new ArrayList ();
307                         }
308
309                         IEnumerable ds = null;
310                         if (useDataSource) {
311                                 ds = GetResolvedDataSource ();
312                         } else {
313                                 int itemCount  = (int) ViewState [ITEMCOUNT];
314                                 if (itemCount != -1)
315                                         ds = new DataSourceInternal (itemCount);
316                         }
317
318                         int index = 0;
319                         if (ds != null) {\r
320                                 if (headerTemplate != null)
321                                         CreateItem (-1, ListItemType.Header, useDataSource, null);
322                                 
323                                 bool even = true;
324                                 foreach (object item in ds){
325                                         if (separatorTemplate != null && index > 0)
326                                                 CreateItem (index - 1, ListItemType.Separator,
327                                                             useDataSource, null);
328
329                                         RepeaterItem repeaterItem;
330                                         ListItemType lType;
331                                         if (!even)
332                                                 lType = ListItemType.AlternatingItem;
333                                         else
334                                                 lType = ListItemType.Item;
335
336                                         repeaterItem = CreateItem (index, lType, useDataSource, item);
337                                         itemsArrayList.Add (repeaterItem);
338                                         index++;
339                                         even = !even;
340                                 }\r
341                                 \r
342                                 if (footerTemplate != null)
343                                         CreateItem (-1, ListItemType.Footer, useDataSource, null);
344                         }
345
346                         if (useDataSource)
347                                 ViewState [ITEMCOUNT] = (ds == null) ? -1 : index;
348                 }
349
350                 protected override bool OnBubbleEvent(object sender, EventArgs e)\r
351                 {\r
352                         bool retVal = false;\r
353                         if(e is RepeaterCommandEventArgs)\r
354                         {\r
355                                 OnItemCommand((RepeaterCommandEventArgs)e);\r
356                                 retVal = true;\r
357                         }\r
358                         return retVal;\r
359                 }\r
360 \r
361                 protected override void OnDataBinding(EventArgs e)\r
362                 {\r
363                         base.OnDataBinding(e);\r
364                         Controls.Clear();\r
365                         ClearChildViewState();\r
366                         CreateControlHierarchy(true);\r
367                         ChildControlsCreated = true;\r
368                 }\r
369 \r
370                 protected virtual void OnItemCommand(RepeaterCommandEventArgs e)\r
371                 {\r
372                         if(Events != null)\r
373                         {\r
374                                 RepeaterCommandEventHandler rceh = (RepeaterCommandEventHandler) \r
375                                                                         Events [ItemCommandEvent];\r
376                                 if(rceh != null)\r
377                                 {\r
378                                         rceh(this, e);\r
379                                 }\r
380                         }\r
381                 }\r
382 \r
383                 protected virtual void OnItemCreated(RepeaterItemEventArgs e)\r
384                 {\r
385                         if(Events != null)\r
386                         {\r
387                                 RepeaterItemEventHandler rceh = (RepeaterItemEventHandler) \r
388                                                                         Events [ItemCreatedEvent];\r
389                                 if(rceh != null)\r
390                                 {\r
391                                         rceh(this, e);\r
392                                 }\r
393                         }\r
394                 }\r
395 \r
396                 protected virtual void OnItemDataBound(RepeaterItemEventArgs e)\r
397                 {\r
398                         if(Events != null)\r
399                         {\r
400                                 RepeaterItemEventHandler rceh = (RepeaterItemEventHandler)\r
401                                                                         Events [ItemDataBoundEvent];\r
402                                 if(rceh != null)\r
403                                 {\r
404                                         rceh(this, e);\r
405                                 }\r
406                         }\r
407                 }\r
408 \r
409                 protected virtual RepeaterItem CreateItem (int itemIndex, ListItemType itemType)\r
410                 {\r
411                         return new RepeaterItem (itemIndex, itemType);\r
412                 }\r
413 \r
414                 protected virtual void InitializeItem (RepeaterItem item)\r
415                 {\r
416                         InstantiateItem (item);\r
417                 }
418                 
419                 #if NET_2_0
420
421                         
422                         // should be `internal protected' (why, oh WHY did they do that !?!)
423                         protected override void OnInit (EventArgs e)
424                         {
425                                 base.OnInit(e);
426                                 inited = true;
427                                 if (!Page.IsPostBack)
428                                         RequiresDataBinding = true;
429                         }
430                         
431                         // should be `internal protected' (why, oh WHY did they do that !?!)
432                         protected override void OnLoad (EventArgs e)
433                         {
434                                 IDataSource ds = GetDataSourceObject () as IDataSource;
435                                 if (ds != null && DataSourceID != "")
436                                         ds.DataSourceChanged += new EventHandler (OnDataSourceChanged);
437                                 
438                                 base.OnLoad(e);
439                         }
440                         
441                         // should be `internal protected' (why, oh WHY did they do that !?!)
442                         protected override void OnPreRender (EventArgs e)
443                         {
444                                 EnsureDataBound ();
445                                 base.OnPreRender (e);
446                         }
447                                 
448                         protected void EnsureDataBound ()
449                         {
450                                 if (RequiresDataBinding && DataSourceID != "")
451                                         DataBind ();
452                         }
453                         
454                         protected virtual object GetDataSourceObject ()
455                         {
456                                 if (DataSourceID != "")
457                                         return (IDataSource) NamingContainer.FindControl (DataSourceID);
458                                 
459                                 return DataSource;
460                         }
461                         
462                         protected virtual IEnumerable GetResolvedDataSource ()
463                         {
464                                 if (DataSource != null && DataSourceID != "")
465                                         throw new HttpException ();
466                                 
467                                 IDataSource ds = this.GetDataSourceObject () as IDataSource;
468                                 if (ds != null && DataSourceID != "")
469                                         return ds.GetView (DataMember).Select ();
470                                 else if (DataSource != null)
471                                         return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
472                                 else
473                                         return null; 
474                         }
475                         
476                         protected void OnDataSourceChanged (object sender, EventArgs e)
477                         {
478                                 RequiresDataBinding = true;
479                         }
480                         
481                         public virtual string DataSourceID {
482                                 get {
483                                         object o = ViewState ["DataSourceID"];
484                                         if (o != null)
485                                                 return (string)o;
486                                         
487                                         return String.Empty;
488                                 }
489                                 set {
490                                         if (inited)
491                                                 RequiresDataBinding = true;
492                                         
493                                         ViewState ["DataSourceID"] = value;
494                                 }
495                         }
496                         
497                         bool requiresDataBinding;
498                         protected bool RequiresDataBinding {
499                                 get { return requiresDataBinding; }
500                                 set { requiresDataBinding = value; }
501                         }
502                         
503                         protected bool inited;
504                                 
505                 #else
506                         IEnumerable GetResolvedDataSource ()
507                         {
508                                 if (DataSource != null)
509                                         return DataSourceHelper.GetResolvedDataSource (DataSource, DataMember);
510                                 else
511                                         return null; 
512                         }
513                 #endif\r
514         }\r
515 }\r