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