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