[bcl] Remove NET_4_0 defines from class libs.
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / DataList.cs
1 //
2 // System.Web.UI.WebControls.DataList.cs
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Globalization;
32 using System.Security.Permissions;
33 using System.Web.Util;
34
35 namespace System.Web.UI.WebControls
36 {
37         // CAS
38         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         // attributes
41         [Designer ("System.Web.UI.Design.WebControls.DataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42         [ControlValueProperty ("SelectedValue")]
43         [Editor ("System.Web.UI.Design.WebControls.DataListComponentEditor, " + Consts.AssemblySystem_Design, "System.ComponentModel.ComponentEditor, " + Consts.AssemblySystem)]
44         public class DataList : BaseDataList, INamingContainer, IRepeatInfoUser
45         {
46                 public const string CancelCommandName = "Cancel";
47                 public const string DeleteCommandName = "Delete";
48                 public const string EditCommandName = "Edit";
49                 public const string SelectCommandName = "Select";
50                 public const string UpdateCommandName = "Update";
51
52                 static readonly object cancelCommandEvent = new object ();
53                 static readonly object deleteCommandEvent = new object ();
54                 static readonly object editCommandEvent = new object ();
55                 static readonly object itemCommandEvent = new object ();
56                 static readonly object itemCreatedEvent = new object ();
57                 static readonly object itemDataBoundEvent = new object ();
58                 static readonly object updateCommandEvent = new object ();
59
60                 TableItemStyle alternatingItemStyle;
61                 TableItemStyle editItemStyle;
62                 TableItemStyle footerStyle;
63                 TableItemStyle headerStyle;
64                 TableItemStyle itemStyle;
65                 TableItemStyle selectedItemStyle;
66                 TableItemStyle separatorStyle;
67
68                 ITemplate alternatingItemTemplate;
69                 ITemplate editItemTemplate;
70                 ITemplate footerTemplate;
71                 ITemplate headerTemplate;
72                 ITemplate itemTemplate;
73                 ITemplate selectedItemTemplate;
74                 ITemplate separatorTemplate;
75
76                 DataListItemCollection items;
77                 ArrayList list;
78                 int idx;
79
80                 public DataList ()
81                 {
82                         idx = -1;
83                 }
84
85                 [DefaultValue (null)]
86                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
87                 [NotifyParentProperty (true)]
88                 [PersistenceMode (PersistenceMode.InnerProperty)]
89                 [WebSysDescription ("")]
90                 [WebCategory ("Style")]
91                 public virtual TableItemStyle AlternatingItemStyle {
92                         get {
93                                 if (alternatingItemStyle == null) {
94                                         alternatingItemStyle = new TableItemStyle ();
95                                         if (IsTrackingViewState)
96                                                 alternatingItemStyle.TrackViewState ();
97                                 }
98                                 return alternatingItemStyle;
99                         }
100                 }
101
102                 [Browsable (false)]
103                 [DefaultValue (null)]
104                 [TemplateContainer (typeof (DataListItem))]
105                 [PersistenceMode (PersistenceMode.InnerProperty)]
106                 [WebSysDescription ("")]
107                 [WebCategory ("Style")]
108                 public virtual ITemplate AlternatingItemTemplate {
109                         get { return alternatingItemTemplate; }
110                         set { alternatingItemTemplate = value; }
111                 }
112
113                 [DefaultValue (-1)]
114                 [WebSysDescription ("")]
115                 [WebCategory ("Misc")]
116                 public virtual int EditItemIndex {
117                         get {
118                                 object o = ViewState ["EditItemIndex"];
119                                 return (o == null) ? -1 : (int) o;
120                         }
121                         set {
122                                 if (value < -1)
123                                         throw new ArgumentOutOfRangeException ("EditItemIndex", "< -1");
124                                 ViewState ["EditItemIndex"] = value;
125                         }
126                 }
127
128                 [DefaultValue (null)]
129                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
130                 [NotifyParentProperty (true)]
131                 [PersistenceMode (PersistenceMode.InnerProperty)]
132                 [WebSysDescription ("")]
133                 [WebCategory ("Style")]
134                 public virtual TableItemStyle EditItemStyle {
135                         get {
136                                 if (editItemStyle == null) {
137                                         editItemStyle = new TableItemStyle ();
138                                         if (IsTrackingViewState)
139                                                 editItemStyle.TrackViewState ();
140                                 }
141                                 return editItemStyle;
142                         }
143                 }
144
145                 [Browsable (false)]
146                 [DefaultValue (null)]
147                 [TemplateContainer (typeof (DataListItem))]
148                 [PersistenceMode (PersistenceMode.InnerProperty)]
149                 [WebSysDescription ("")]
150                 [WebCategory ("Style")]
151                 public virtual ITemplate EditItemTemplate {
152                         get { return editItemTemplate; }
153                         set { editItemTemplate = value; }
154                 }
155
156                 [DefaultValue (false)]
157                 [WebSysDescription ("")]
158                 [WebCategory ("Misc")]
159                 public virtual bool ExtractTemplateRows {
160                         get {
161                                 object o = ViewState ["ExtractTemplateRows"];
162                                 return (o == null) ? false : (bool) o;
163                         }
164                         set { ViewState ["ExtractTemplateRows"] = value; }
165                 }
166
167                 [DefaultValue (null)]
168                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
169                 [NotifyParentProperty (true)]
170                 [PersistenceMode (PersistenceMode.InnerProperty)]
171                 [WebSysDescription ("")]
172                 [WebCategory ("Style")]
173                 public virtual TableItemStyle FooterStyle {
174                         get {
175                                 if (footerStyle == null) {
176                                         footerStyle = new TableItemStyle ();
177                                         if (IsTrackingViewState)
178                                                 footerStyle.TrackViewState ();
179                                 }
180                                 return footerStyle;
181                         }
182                 }
183
184                 [Browsable (false)]
185                 [DefaultValue (null)]
186                 [TemplateContainer (typeof (DataListItem))]
187                 [PersistenceMode (PersistenceMode.InnerProperty)]
188                 [WebSysDescription ("")]
189                 [WebCategory ("Style")]
190                 public virtual ITemplate FooterTemplate {
191                         get { return footerTemplate; }
192                         set { footerTemplate = value; }
193                 }
194
195                 // yes! they do NOT match in fx1.1
196                 [DefaultValue (GridLines.None)]
197                 public override GridLines GridLines {
198                         get {
199                                 if (!ControlStyleCreated)
200                                         return GridLines.None;
201                                 return TableStyle.GridLines;
202                         }
203                         set { TableStyle.GridLines = value; }
204                 }
205
206                 [DefaultValue (null)]
207                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
208                 [NotifyParentProperty (true)]
209                 [PersistenceMode (PersistenceMode.InnerProperty)]
210                 [WebSysDescription ("")]
211                 [WebCategory ("Style")]
212                 public virtual TableItemStyle HeaderStyle {
213                         get {
214                                 if (headerStyle == null) {
215                                         headerStyle = new TableItemStyle ();
216                                         if (IsTrackingViewState)
217                                                 headerStyle.TrackViewState ();
218                                 }
219                                 return headerStyle;
220                         }
221                 }
222
223                 [Browsable (false)]
224                 [DefaultValue (null)]
225                 [TemplateContainer (typeof (DataListItem))]
226                 [PersistenceMode (PersistenceMode.InnerProperty)]
227                 [WebSysDescription ("")]
228                 [WebCategory ("Style")]
229                 public virtual ITemplate HeaderTemplate {
230                         get { return headerTemplate; }
231                         set { headerTemplate = value; }
232                 }
233
234                 [Browsable (false)]
235                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
236                 [WebSysDescription ("")]
237                 [WebCategory ("Style")]
238                 public virtual DataListItemCollection Items {
239                         get {
240                                 if (items == null)
241                                         items = new DataListItemCollection (ItemList);
242                                 return items;
243                         }
244                 }
245
246                 [DefaultValue (null)]
247                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
248                 [NotifyParentProperty (true)]
249                 [PersistenceMode (PersistenceMode.InnerProperty)]
250                 [WebSysDescription ("")]
251                 [WebCategory ("Style")]
252                 public virtual TableItemStyle ItemStyle {
253                         get {
254                                 if (itemStyle == null) {
255                                         itemStyle = new TableItemStyle ();
256                                         if (IsTrackingViewState)
257                                                 itemStyle.TrackViewState ();
258                                 }
259                                 return itemStyle;
260                         }
261                 }
262
263                 [Browsable (false)]
264                 [DefaultValue (null)]
265                 [TemplateContainer (typeof (DataListItem))]
266                 [PersistenceMode (PersistenceMode.InnerProperty)]
267                 [WebSysDescription ("")]
268                 [WebCategory ("Style")]
269                 public virtual ITemplate ItemTemplate {
270                         get { return itemTemplate; }
271                         set { itemTemplate = value; }
272                 }
273
274                 [DefaultValue (0)]
275                 [WebSysDescription ("")]
276                 [WebCategory ("Layout")]
277                 public virtual int RepeatColumns {
278                         get {
279                                 object o = ViewState ["RepeatColumns"];
280                                 return (o == null) ? 0 : (int) o;
281                         }
282                         set { 
283                                 if (value < 0)
284                                         throw new ArgumentOutOfRangeException ("value", "RepeatColumns value has to be 0 for 'not set' or > 0.");
285                                 
286                                 ViewState ["RepeatColumns"] = value; 
287                         }
288                 }
289
290                 [DefaultValue (RepeatDirection.Vertical)]
291                 [WebSysDescription ("")]
292                 [WebCategory ("Layout")]
293                 public virtual RepeatDirection RepeatDirection {
294                         get {
295                                 object o = ViewState ["RepeatDirection"];
296                                 return (o == null) ? RepeatDirection.Vertical : (RepeatDirection) o;
297                         }
298                         set { ViewState ["RepeatDirection"] = value; }
299                 }
300
301                 [DefaultValue (RepeatLayout.Table)]
302                 [WebSysDescription ("")]
303                 [WebCategory ("Layout")]
304                 public virtual RepeatLayout RepeatLayout {
305                         get {
306                                 object o = ViewState ["RepeatLayout"];
307                                 return (o == null) ? RepeatLayout.Table : (RepeatLayout) o;
308                         }
309                         set {
310                                 if (value == RepeatLayout.OrderedList || value == RepeatLayout.UnorderedList)
311                                         throw new ArgumentOutOfRangeException (String.Format ("DataList does not support the '{0}' layout.", value));
312                                 ViewState ["RepeatLayout"] = value;
313                         }
314                 }
315
316                 [Bindable (true)]
317                 [DefaultValue (-1)]
318                 [WebSysDescription ("")]
319                 [WebCategory ("Layout")]
320                 public virtual int SelectedIndex {
321                         get {
322                                 object o = ViewState ["SelectedIndex"];
323                                 return (o == null) ? -1 : (int) o;
324                         }
325                         set {
326                                 if (value < -1)
327                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "< -1");
328                                 ViewState ["SelectedIndex"] = value;
329                         }
330                 }
331
332                 [Browsable (false)]
333                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
334                 [WebSysDescription ("")]
335                 [WebCategory ("Layout")]
336                 public virtual DataListItem SelectedItem {
337                         get {
338                                 if (SelectedIndex < 0)
339                                         return null;
340                                 if (SelectedIndex >= Items.Count)
341                                         throw new ArgumentOutOfRangeException ("SelectedItem", ">= Items.Count");
342                                 return items [SelectedIndex];
343                         }
344                 }
345
346                 [DefaultValue (null)]
347                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
348                 [NotifyParentProperty (true)]
349                 [PersistenceMode (PersistenceMode.InnerProperty)]
350                 [WebSysDescription ("")]
351                 [WebCategory ("Style")]
352                 public virtual TableItemStyle SelectedItemStyle {
353                         get {
354                                 if (selectedItemStyle == null) {
355                                         selectedItemStyle = new TableItemStyle ();
356                                         if (IsTrackingViewState)
357                                                 selectedItemStyle.TrackViewState ();
358                                 }
359                                 return selectedItemStyle;
360                         }
361                 }
362
363                 [Browsable (false)]
364                 [DefaultValue (null)]
365                 [TemplateContainer (typeof (DataListItem))]
366                 [PersistenceMode (PersistenceMode.InnerProperty)]
367                 [WebSysDescription ("")]
368                 [WebCategory ("Style")]
369                 public virtual ITemplate SelectedItemTemplate {
370                         get { return selectedItemTemplate; }
371                         set { selectedItemTemplate = value; }
372                 }
373
374                 [DefaultValue (null)]
375                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
376                 [NotifyParentProperty (true)]
377                 [PersistenceMode (PersistenceMode.InnerProperty)]
378                 [WebSysDescription ("")]
379                 [WebCategory ("Style")]
380                 public virtual TableItemStyle SeparatorStyle {
381                         get {
382                                 if (separatorStyle == null) {
383                                         separatorStyle = new TableItemStyle ();
384                                         if (IsTrackingViewState)
385                                                 separatorStyle.TrackViewState ();
386                                 }
387                                 return separatorStyle;
388                         }
389                 }
390
391                 [Browsable (false)]
392                 [DefaultValue (null)]
393                 [TemplateContainer (typeof (DataListItem))]
394                 [PersistenceMode (PersistenceMode.InnerProperty)]
395                 [WebSysDescription ("")]
396                 [WebCategory ("Style")]
397                 public virtual ITemplate SeparatorTemplate {
398                         get { return separatorTemplate; }
399                         set { separatorTemplate = value; }
400                 }
401
402                 [DefaultValue (true)]
403                 [WebSysDescription ("")]
404                 [WebCategory ("Appearance")]
405                 public virtual bool ShowFooter {
406                         get {
407                                 object o = ViewState ["ShowFooter"];
408                                 return (o == null) ? true : (bool) o;
409                         }
410                         set { ViewState ["ShowFooter"] = value; }
411                 }
412
413                 [DefaultValue (true)]
414                 [WebSysDescription ("")]
415                 [WebCategory ("Appearance")]
416                 public virtual bool ShowHeader {
417                         get {
418                                 object o = ViewState ["ShowHeader"];
419                                 return (o == null) ? true : (bool) o;
420                         }
421                         set { ViewState ["ShowHeader"] = value; }
422                 }
423
424                 [MonoTODO ("incomplete")]
425                 [Browsable (false)]
426                 public object SelectedValue {
427                         get {
428                                 if (DataKeyField.Length == 0)
429                                         throw new InvalidOperationException (Locale.GetText ("No DataKeyField present."));
430
431                                 int idx = SelectedIndex;
432                                 if ((idx >= 0) && (idx < DataKeys.Count))
433                                         return DataKeys [idx];
434
435                                 return null;
436                         }
437                 }
438
439                 protected override HtmlTextWriterTag TagKey {
440                         get { return HtmlTextWriterTag.Table; }
441                 }
442
443                 TableStyle TableStyle {
444                         // this will throw an InvalidCasException just like we need
445                         get { return (TableStyle) ControlStyle; }
446                 }
447                 
448                 ArrayList ItemList {
449                         get {
450                                 if (list == null)
451                                         list = new ArrayList ();
452                                 return list;
453                         }
454                 }
455
456                 void DoItem (int i, ListItemType t, object d, bool databind)
457                 {
458                         DataListItem itm = CreateItem (i, t);
459                         if (databind)
460                                 itm.DataItem = d;
461                         DataListItemEventArgs e = new DataListItemEventArgs (itm);
462                         InitializeItem (itm);
463                         
464                         //
465                         // It is very important that this be called *before* data
466                         // binding. Otherwise, we won't save our state in the viewstate.
467                         //
468                         Controls.Add (itm);
469                         if (i != -1)
470                                 ItemList.Add (itm);
471
472                         OnItemCreated (e);
473
474                         if (databind) {
475                                 itm.DataBind ();
476                                 OnItemDataBound (e);
477                                 itm.DataItem = null;
478                         }
479                 }
480
481                 void DoItemInLoop (int i, object d, bool databind, ListItemType type)
482                 {
483                         DoItem (i, type, d, databind);
484                         if (SeparatorTemplate != null)
485                                 DoItem (i, ListItemType.Separator, null, databind);
486
487                 }
488
489                 protected override void CreateControlHierarchy (bool useDataSource)
490                 {
491                         Controls.Clear();
492                         ItemList.Clear ();
493
494                         IEnumerable ds = null;
495                         ArrayList keys = null;
496
497                         if (useDataSource) {
498                                 idx = 0;
499                                 if (IsBoundUsingDataSourceID)
500                                         ds = GetData();
501                                 else
502                                         ds = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
503                                 keys = DataKeysArray;
504                                 keys.Clear ();
505                         } else
506                                 idx = (int) ViewState ["Items"];
507
508                         if ((ds == null) && (idx == 0))
509                                 return;
510
511                         if (headerTemplate != null)
512                                 DoItem (-1, ListItemType.Header, null, useDataSource);
513
514                         // items
515                         int selected_index = SelectedIndex;
516                         int edit_item_index = EditItemIndex;
517                         ListItemType type;
518                         if (ds != null) {
519                                 string key = DataKeyField;
520                                 foreach (object o in ds) {
521                                         if (useDataSource && !String.IsNullOrEmpty (key))
522                                                 keys.Add (DataBinder.GetPropertyValue (o, key));
523                                         type = ListItemType.Item;
524                                         if (idx == edit_item_index) 
525                                                 type = ListItemType.EditItem;
526                                         else if (idx == selected_index) 
527                                                 type = ListItemType.SelectedItem;
528                                         else if ((idx & 1) != 0) 
529                                                 type = ListItemType.AlternatingItem;
530
531                                         DoItemInLoop (idx, o, useDataSource, type);
532                                         idx++;
533                                 }
534                         } else {
535                                 for (int i = 0; i < idx; i++) {
536                                         type = ListItemType.Item;
537                                         if (i == edit_item_index) 
538                                                 type = ListItemType.EditItem;
539                                         else if (i == selected_index) 
540                                                 type = ListItemType.SelectedItem;
541                                         else if ((i & 1) != 0) 
542                                                 type = ListItemType.AlternatingItem;
543
544                                         DoItemInLoop (i, null, useDataSource, type);
545                                 }
546                         }
547
548                         if (footerTemplate != null)
549                                 DoItem (-1, ListItemType.Footer, null, useDataSource);
550
551                         ViewState ["Items"] = idx;
552                 }
553
554                 protected override Style CreateControlStyle ()
555                 {
556                         // not kept (directly) in the DataList ViewState
557                         TableStyle tableStyle = new TableStyle ();
558                         tableStyle.CellSpacing = 0;
559                         return tableStyle;
560                 }
561
562                 protected virtual DataListItem CreateItem (int itemIndex, ListItemType itemType)
563                 {
564                         return new DataListItem (itemIndex, itemType);
565                 }
566
567                 protected virtual void InitializeItem (DataListItem item)
568                 {
569                         ITemplate t = null;
570                         
571                         switch (item.ItemType) {
572                                 case ListItemType.Header:
573                                         t = HeaderTemplate;
574                                         break;
575                                 case ListItemType.Footer:
576                                         t = FooterTemplate;
577                                         break;  
578                                 case ListItemType.Separator:
579                                         t = SeparatorTemplate;
580                                         break;
581                                 case ListItemType.Item:
582                                 case ListItemType.AlternatingItem:
583                                 case ListItemType.SelectedItem:
584                                 case ListItemType.EditItem:
585                                         if ((item.ItemType == ListItemType.EditItem) && (EditItemTemplate != null))
586                                                 t = EditItemTemplate;
587                                         else if ((item.ItemType == ListItemType.SelectedItem) && (SelectedItemTemplate != null))
588                                                 t = SelectedItemTemplate;
589                                         else if ((item.ItemType == ListItemType.AlternatingItem) && (AlternatingItemTemplate != null))
590                                                 t = AlternatingItemTemplate;
591                                         else
592                                                 t = ItemTemplate;
593                                         break;
594                         }
595
596                         if (t != null)
597                                 t.InstantiateIn (item);
598                 }
599
600                 protected override void LoadViewState (object savedState)
601                 {
602                         object[] state = (object[]) savedState;
603                         base.LoadViewState (state [0]);
604                         if (state [1] != null)
605                                 ItemStyle.LoadViewState (state [1]);
606                         if (state [2] != null)
607                                 SelectedItemStyle.LoadViewState (state [2]);
608                         if (state [3] != null)
609                                 AlternatingItemStyle.LoadViewState (state [3]);
610                         if (state [4] != null)
611                                 EditItemStyle.LoadViewState (state [4]);
612                         if (state [5] != null)
613                                 SeparatorStyle.LoadViewState (state [5]);
614                         if (state [6] != null)
615                                 HeaderStyle.LoadViewState (state [6]);
616                         if (state [7] != null)
617                                 FooterStyle.LoadViewState (state [7]);
618                         if (state [8] != null)
619                                 ControlStyle.LoadViewState (state [8]);
620                 }
621
622                 protected override bool OnBubbleEvent (object source, EventArgs e)
623                 {
624                         DataListCommandEventArgs dlca = (e as DataListCommandEventArgs);
625                         if (dlca == null)
626                                 return false;
627
628                         string cn = dlca.CommandName;
629                         CultureInfo inv = Helpers.InvariantCulture;
630
631                         OnItemCommand (dlca);
632                         if (String.Compare (cn, CancelCommandName, true, inv) == 0)
633                                 OnCancelCommand (dlca);
634                         else if (String.Compare (cn, DeleteCommandName, true, inv) == 0)
635                                 OnDeleteCommand (dlca);
636                         else if (String.Compare (cn, EditCommandName, true, inv) == 0)
637                                 OnEditCommand (dlca);
638                         else if (String.Compare (cn, SelectCommandName, true, inv) == 0) {
639                                 SelectedIndex = dlca.Item.ItemIndex;
640                                 OnSelectedIndexChanged (dlca);
641                         } else if (String.Compare (cn, UpdateCommandName, true, inv) == 0)
642                                 OnUpdateCommand (dlca);
643                         
644                         return true;
645                 }
646
647                 protected virtual void OnCancelCommand (DataListCommandEventArgs e)
648                 {
649                         DataListCommandEventHandler cancelCommand = (DataListCommandEventHandler) Events [cancelCommandEvent];
650                         if (cancelCommand != null)
651                                 cancelCommand (this, e);
652                 }
653
654                 protected virtual void OnDeleteCommand (DataListCommandEventArgs e)
655                 {
656                         DataListCommandEventHandler deleteCommand = (DataListCommandEventHandler) Events [deleteCommandEvent];
657                         if (deleteCommand != null)
658                                 deleteCommand (this, e);
659                 }
660
661                 protected virtual void OnEditCommand (DataListCommandEventArgs e)
662                 {
663                         DataListCommandEventHandler editCommand = (DataListCommandEventHandler) Events [editCommandEvent];
664                         if (editCommand != null)
665                                 editCommand (this, e);
666                 }
667
668                 protected internal override void OnInit (EventArgs e)
669                 {
670                         // EditItemIndex and SelectedIndex now use the Control State (i.e not the
671                         // View State)
672                         Page page = Page;
673                         if (page != null)
674                                 page.RegisterRequiresControlState (this);
675                         base.OnInit (e);
676                 }
677
678                 protected virtual void OnItemCommand (DataListCommandEventArgs e)
679                 {
680                         DataListCommandEventHandler itemCommand = (DataListCommandEventHandler) Events [itemCommandEvent];
681                         if (itemCommand != null)
682                                 itemCommand (this, e);
683                 }
684
685                 protected virtual void OnItemCreated (DataListItemEventArgs e)
686                 {
687                         DataListItemEventHandler itemCreated = (DataListItemEventHandler) Events [itemCreatedEvent];
688                         if (itemCreated != null)
689                                 itemCreated (this, e);
690                 }
691
692                 protected virtual void OnItemDataBound (DataListItemEventArgs e)
693                 {
694                         DataListItemEventHandler itemDataBound = (DataListItemEventHandler) Events [itemDataBoundEvent];
695                         if (itemDataBound != null)
696                                 itemDataBound (this, e);
697                 }
698
699                 protected virtual void OnUpdateCommand (DataListCommandEventArgs e)
700                 {
701                         DataListCommandEventHandler updateCommand = (DataListCommandEventHandler) Events [updateCommandEvent];
702                         if (updateCommand != null)
703                                 updateCommand (this, e);
704                 }
705
706                 protected override void PrepareControlHierarchy ()
707                 {
708                         if (!HasControls () || Controls.Count == 0)
709                                 return; // No one called CreateControlHierarchy() with DataSource != null
710
711                         Style alt = null;
712                         foreach (DataListItem item in Controls) {
713                                 switch (item.ItemType) {
714                                         case ListItemType.Item:
715                                                 item.MergeStyle (itemStyle);
716                                                 break;
717                                         case ListItemType.AlternatingItem:
718                                                 if (alt == null) {
719                                                         if (alternatingItemStyle != null) {
720                                                                 alt = new TableItemStyle ();
721                                                                 alt.CopyFrom (itemStyle);
722                                                                 alt.CopyFrom (alternatingItemStyle);
723                                                         } else
724                                                                 alt = itemStyle;
725                                                 }
726
727                                                 item.MergeStyle (alt);
728                                                 break;
729                                         case ListItemType.EditItem:
730                                                 if (editItemStyle != null)
731                                                         item.MergeStyle (editItemStyle);
732                                                 else
733                                                         item.MergeStyle (itemStyle);
734                                                 break;
735                                         case ListItemType.Footer:
736                                                 if (!ShowFooter) {
737                                                         item.Visible = false;
738                                                         break;
739                                                 }
740                                                 if (footerStyle != null)
741                                                         item.MergeStyle (footerStyle);
742                                                 break;
743                                         case ListItemType.Header:
744                                                 if (!ShowHeader) {
745                                                         item.Visible = false;
746                                                         break;
747                                                 }
748                                                 if (headerStyle != null)
749                                                         item.MergeStyle (headerStyle);
750                                                 break;
751                                         case ListItemType.SelectedItem:
752                                                 if (selectedItemStyle != null)
753                                                         item.MergeStyle (selectedItemStyle);
754                                                 else
755                                                         item.MergeStyle (itemStyle);
756                                                 break;
757                                         case ListItemType.Separator:
758                                                 if (separatorStyle != null)
759                                                         item.MergeStyle(separatorStyle);
760                                                 else
761                                                         item.MergeStyle (itemStyle);
762                                                 break;
763                                 }
764                         }
765                 }
766
767                 protected internal override void RenderContents (HtmlTextWriter writer)
768                 {
769                         if (Items.Count == 0)
770                                 return;                 
771
772                         RepeatInfo ri = new RepeatInfo ();
773                         ri.RepeatColumns = RepeatColumns;
774                         ri.RepeatDirection = RepeatDirection;
775                         ri.RepeatLayout = RepeatLayout;
776                         ri.CaptionAlign = CaptionAlign;
777                         ri.Caption = Caption;
778                         ri.UseAccessibleHeader = UseAccessibleHeader;
779 /*
780 // debugging stuff that I prefer to keep for a while
781 Console.WriteLine ("RepeatColumns {0}", ri.RepeatColumns);
782 Console.WriteLine ("RepeatDirection {0}", ri.RepeatDirection);
783 Console.WriteLine ("RepeatLayout {0}", ri.RepeatLayout);
784 Console.WriteLine ("OuterTableImplied {0}", ExtractTemplateRows);
785 Console.WriteLine ("IRepeatInfoUser.HasFooter {0}", (ShowFooter && (footerTemplate != null)));
786 Console.WriteLine ("IRepeatInfoUser.HasHeader {0}", (ShowHeader && (headerTemplate != null)));
787 Console.WriteLine ("IRepeatInfoUser.HasSeparators {0}", (separatorTemplate != null));
788 Console.WriteLine ("IRepeatInfoUser.RepeatedItemCount {0}", Items.Count);
789 for (int i=0; i < Items.Count; i++) {
790         DataListItem dli = Items [i];
791         Console.WriteLine ("{0}: Index {1}, Type {2}", i, dli.ItemIndex, dli.ItemType);
792 }
793 */
794                         bool extract = ExtractTemplateRows;
795                         if (extract) {
796                                 ri.OuterTableImplied = true;
797                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
798                                 if (ControlStyleCreated)
799                                         ControlStyle.AddAttributesToRender (writer);
800                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
801                                 ri.RenderRepeater (writer, this, ControlStyle, this);
802                                 writer.RenderEndTag ();
803                         } else
804                                 ri.RenderRepeater (writer, this, ControlStyle, this);
805                 }
806
807                 protected override object SaveViewState ()
808                 {
809                         object[] state = new object [9];
810                         state[0] = base.SaveViewState ();
811                         if (itemStyle != null)
812                                 state [1] = itemStyle.SaveViewState ();
813                         if (selectedItemStyle != null)
814                                 state [2] = selectedItemStyle.SaveViewState ();
815                         if (alternatingItemStyle != null)
816                                 state [3] = alternatingItemStyle.SaveViewState ();
817                         if (editItemStyle != null)
818                                 state [4] = editItemStyle.SaveViewState ();
819                         if (separatorStyle != null)
820                                 state [5] = separatorStyle.SaveViewState ();
821                         if (headerStyle != null)
822                                 state [6] = headerStyle.SaveViewState ();
823                         if (footerStyle != null)
824                                 state [7] = footerStyle.SaveViewState ();
825                         if (ControlStyleCreated)
826                                 state [8] = ControlStyle.SaveViewState ();
827                         return state;
828                 }
829
830                 protected override void TrackViewState ()
831                 {
832                         base.TrackViewState ();
833                         if (alternatingItemStyle != null)
834                                 alternatingItemStyle.TrackViewState ();
835                         if (editItemStyle != null)
836                                 editItemStyle.TrackViewState ();
837                         if (footerStyle != null)
838                                 footerStyle.TrackViewState ();
839                         if (headerStyle != null)
840                                 headerStyle.TrackViewState ();
841                         if (itemStyle != null)
842                                 itemStyle.TrackViewState ();
843                         if (selectedItemStyle != null)
844                                 selectedItemStyle.TrackViewState ();
845                         if (separatorStyle != null)
846                                 separatorStyle.TrackViewState ();
847                         if (ControlStyleCreated)
848                                 ControlStyle.TrackViewState ();
849                 }
850
851
852                 [WebSysDescription ("")]
853                 [WebCategory ("Action")]
854                 public event DataListCommandEventHandler CancelCommand {
855                         add { Events.AddHandler (cancelCommandEvent, value); }
856                         remove { Events.RemoveHandler (cancelCommandEvent, value); }
857                 }
858
859                 [WebSysDescription ("")]
860                 [WebCategory ("Action")]
861                 public event DataListCommandEventHandler DeleteCommand {
862                         add { Events.AddHandler (deleteCommandEvent, value); }
863                         remove { Events.RemoveHandler (deleteCommandEvent, value); }
864                 }
865
866                 [WebSysDescription ("")]
867                 [WebCategory ("Action")]
868                 public event DataListCommandEventHandler EditCommand {
869                         add { Events.AddHandler (editCommandEvent, value); }
870                         remove { Events.RemoveHandler (editCommandEvent, value); }
871                 }
872
873                 [WebSysDescription ("")]
874                 [WebCategory ("Action")]
875                 public event DataListCommandEventHandler ItemCommand {
876                         add { Events.AddHandler (itemCommandEvent, value); }
877                         remove { Events.RemoveHandler (itemCommandEvent, value); }
878                 }
879
880                 [WebSysDescription ("")]
881                 [WebCategory ("Action")]
882                 public event DataListItemEventHandler ItemCreated {
883                         add { Events.AddHandler (itemCreatedEvent, value); }
884                         remove { Events.RemoveHandler (itemCreatedEvent, value); }
885                 }
886
887                 [WebSysDescription ("")]
888                 [WebCategory ("Action")]
889                 public event DataListItemEventHandler ItemDataBound {
890                         add { Events.AddHandler (itemDataBoundEvent, value); }
891                         remove { Events.RemoveHandler (itemDataBoundEvent, value); }
892                 }
893
894                 [WebSysDescription ("")]
895                 [WebCategory ("Action")]
896                 public event DataListCommandEventHandler UpdateCommand {
897                         add { Events.AddHandler (updateCommandEvent, value); }
898                         remove { Events.RemoveHandler (updateCommandEvent, value); }
899                 }
900
901
902                 // IRepeatInfoUser support
903
904                 bool IRepeatInfoUser.HasFooter {
905                         get { return (ShowFooter && (footerTemplate != null)); }
906                 }
907
908                 bool IRepeatInfoUser.HasHeader {
909                         get { return (ShowHeader && (headerTemplate != null)); }
910                 }
911                 
912                 bool IRepeatInfoUser.HasSeparators {
913                         get { return (separatorTemplate != null); }
914                 }
915
916                 // don't include header, footer and separators in the count
917                 int IRepeatInfoUser.RepeatedItemCount {
918                         get {
919                                 if (idx == -1) {
920                                         object o = ViewState ["Items"];
921                                         idx = (o == null) ? 0 : (int) o;
922                                 }
923                                 return idx;
924                         }
925                 }
926
927                 Style IRepeatInfoUser.GetItemStyle (ListItemType itemType, int repeatIndex)
928                 {
929                         DataListItem item = null;
930                         switch (itemType) {
931                                 case ListItemType.Header:
932                                 case ListItemType.Footer:
933                                         if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
934                                                 throw new ArgumentOutOfRangeException ();
935
936                                         item = FindFirstItem (itemType);
937                                         break;
938                                 case ListItemType.Item:
939                                 case ListItemType.AlternatingItem:
940                                 case ListItemType.SelectedItem:
941                                 case ListItemType.EditItem:
942                                         if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
943                                                 throw new ArgumentOutOfRangeException ();
944
945                                         item = FindBestItem (repeatIndex);
946                                         break;
947                                 case ListItemType.Separator:
948                                         if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
949                                                 throw new ArgumentOutOfRangeException ();
950
951                                         item = FindSpecificItem (itemType, repeatIndex);
952                                         break;
953                                 default:
954                                         item = null;
955                                         break;
956                         }
957
958                         if (item == null || item.ControlStyleCreated == false)
959                                 return null;
960
961                         return item.ControlStyle;
962                 }
963
964                 // Header and Footer don't have a "real" index (-1)
965                 DataListItem FindFirstItem (ListItemType itemType)
966                 {
967                         for (int i = 0; i < Controls.Count; i++) {
968                                 DataListItem item = (Controls [i] as DataListItem);
969                                 if ((item != null) && (item.ItemType == itemType))
970                                         return item;
971                         }
972                         return null;
973                 }
974
975                 // Both Type and Index must match (e.g. Separator)
976                 DataListItem FindSpecificItem (ListItemType itemType, int repeatIndex)
977                 {
978                         for (int i = 0; i < Controls.Count; i++) {
979                                 DataListItem item = (Controls [i] as DataListItem);
980                                 if ((item != null) && (item.ItemType == itemType) && (item.ItemIndex == repeatIndex))
981                                         return item;
982                         }
983                         return null;
984                 }
985
986                 // we get call for Item even for AlternatingItem :(
987                 DataListItem FindBestItem (int repeatIndex)
988                 {
989                         for (int i = 0; i < Controls.Count; i++) {
990                                 DataListItem item = (Controls [i] as DataListItem);
991                                 if ((item != null) && (item.ItemIndex == repeatIndex)) {
992                                         switch (item.ItemType) {
993                                                 case ListItemType.Item:
994                                                 case ListItemType.AlternatingItem:
995                                                 case ListItemType.SelectedItem:
996                                                 case ListItemType.EditItem:
997                                                         return item;
998                                                 default:
999                                                         return null;
1000                                         }
1001                                 }
1002                         }
1003                         return null;
1004                 }
1005
1006                 void IRepeatInfoUser.RenderItem (ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
1007                 {
1008                         // if possible take the easy way out...
1009                         if (!HasControls ())
1010                                 return;
1011
1012                         DataListItem item = null;
1013                         switch (itemType) {
1014                                 case ListItemType.Header:
1015                                 case ListItemType.Footer:
1016                                         item = FindFirstItem (itemType);
1017                                         break;
1018                                 case ListItemType.Item:
1019                                 case ListItemType.AlternatingItem:
1020                                 case ListItemType.SelectedItem:
1021                                 case ListItemType.EditItem:
1022                                         item = FindBestItem (repeatIndex);
1023                                         break;
1024                                 case ListItemType.Separator:
1025                                         item = FindSpecificItem (itemType, repeatIndex);
1026                                         break;
1027                         }
1028
1029                         if (item != null) {
1030                                 bool extract = ExtractTemplateRows;
1031                                 bool table = (RepeatLayout == RepeatLayout.Table);
1032                                 if (!table || extract) {
1033                                         // sadly RepeatInfo doesn't support Style for RepeatLayout.Flow
1034                                         Style s = (this as IRepeatInfoUser).GetItemStyle (itemType, repeatIndex);
1035                                         if (s != null)
1036                                                 item.ControlStyle.CopyFrom (s);
1037                                 }
1038 //Console.WriteLine ("RenderItem #{0} type {1}", repeatIndex, itemType);
1039                                 item.RenderItem (writer, extract, table);
1040                         } else {
1041 //Console.WriteLine ("Couldn't find #{0} type {1} out of {2} items / {3} controls", repeatIndex, itemType, Items.Count, Controls.Count);
1042                         }
1043                 }
1044         }
1045 }