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