DataList.cs: Fixed LoadViewState method
[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
536                         IEnumerable ds = null;
537                         ArrayList keys = null;
538
539                         if (useDataSource) {
540                                 idx = 0;
541 #if NET_2_0
542                                 if (IsBoundUsingDataSourceID)
543                                         ds = GetData();
544                                 else
545 #endif
546                                 ds = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
547                                 keys = DataKeysArray;
548                                 keys.Clear ();
549                         } else {
550                                 idx = (int) ViewState ["Items"];
551                         }
552
553                         if ((ds == null) && (idx == 0))
554                                 return;
555
556                         if (headerTemplate != null)
557                                 DoItem (-1, ListItemType.Header, null, useDataSource);
558
559                         // items
560                         int selected_index = SelectedIndex;
561                         int edit_item_index = EditItemIndex;
562                         ListItemType type;
563                         if (ds != null) {
564                                 string key = DataKeyField;
565                                 foreach (object o in ds) {
566                                         if (useDataSource && key != "")
567                                                 keys.Add (DataBinder.GetPropertyValue (o, key));
568                                         type = ListItemType.Item;
569                                         if (idx == edit_item_index) 
570                                                 type = ListItemType.EditItem;
571                                         else if (idx == selected_index) 
572                                                 type = ListItemType.SelectedItem;
573                                         else if (idx % 2 != 0) 
574                                                 type = ListItemType.AlternatingItem;
575
576                                         DoItemInLoop (idx, o, useDataSource, type);
577                                         idx++;
578                                 }
579                         } else {
580                                 for (int i = 0; i < idx; i++) {
581                                         type = ListItemType.Item;
582                                         if (idx == edit_item_index) 
583                                                 type = ListItemType.EditItem;
584                                         else if (idx == selected_index) 
585                                                 type = ListItemType.SelectedItem;
586                                         else if (idx % 2 != 0) 
587                                                 type = ListItemType.AlternatingItem;
588
589                                         DoItemInLoop (i, null, useDataSource, type);
590                                 }
591                         }
592
593                         if (footerTemplate != null)
594                                 DoItem (-1, ListItemType.Footer, null, useDataSource);
595
596                         ViewState ["Items"] = idx;
597                 }
598
599                 protected override Style CreateControlStyle ()
600                 {
601 #if NET_2_0
602                         // not kept (directly) in the DataList ViewState
603                         return new TableStyle ();
604 #else
605                         TableStyle tableStyle = new TableStyle (ViewState);
606                         tableStyle.CellSpacing = 0;
607                         return tableStyle;
608 #endif
609                 }
610
611                 protected virtual DataListItem CreateItem (int itemIndex, ListItemType itemType)
612                 {
613                         return new DataListItem (itemIndex, itemType);
614                 }
615
616                 protected virtual void InitializeItem (DataListItem item)
617                 {
618                         ITemplate t = null;
619                         
620                         switch (item.ItemType) {
621                         case ListItemType.Header:
622                                 t = HeaderTemplate;
623                                 break;
624                         case ListItemType.Footer:
625                                 t = FooterTemplate;
626                                 break;  
627                         case ListItemType.Separator:
628                                 t = SeparatorTemplate;
629                                 break;
630                         case ListItemType.Item:
631                         case ListItemType.AlternatingItem:
632                         case ListItemType.SelectedItem:
633                         case ListItemType.EditItem:
634                                 int index = item.ItemIndex;
635                                 if ((SelectedIndex == index) && (SelectedItemTemplate != null))
636                                         t = SelectedItemTemplate;
637                                 else if ((EditItemIndex == index) && (EditItemTemplate != null))
638                                         t = EditItemTemplate;
639                                 else if (((index & 1) == 0) || (alternatingItemTemplate == null))
640                                         t = ItemTemplate;
641                                 else
642                                         t = alternatingItemTemplate;
643                                 break;
644                         }
645
646                         if (t != null)
647                                 t.InstantiateIn (item);
648                 }
649
650                 protected override void LoadViewState (object savedState)
651                 {
652                         object[] state = (object[]) savedState;
653 #if NET_2_0
654                         base.LoadViewState (state [8]);
655 #else
656                         base.LoadViewState (state [0]);
657 #endif
658                         if (state [1] != null)
659                                 ItemStyle.LoadViewState (state [1]);
660                         if (state [2] != null)
661                                 SelectedItemStyle.LoadViewState (state [2]);
662                         if (state [3] != null)
663                                 AlternatingItemStyle.LoadViewState (state [3]);
664                         if (state [4] != null)
665                                 EditItemStyle.LoadViewState (state [4]);
666                         if (state [5] != null)
667                                 SeparatorStyle.LoadViewState (state [5]);
668                         if (state [6] != null)
669                                 HeaderStyle.LoadViewState (state [6]);
670                         if (state [7] != null)
671                                 FooterStyle.LoadViewState (state [7]);
672                 }
673
674                 protected override bool OnBubbleEvent (object source, EventArgs e)
675                 {
676                         DataListCommandEventArgs dlca = (e as DataListCommandEventArgs);
677                         if (dlca == null)
678                                 return false;
679
680                         string cn = dlca.CommandName;
681                         CultureInfo inv = CultureInfo.InvariantCulture;
682
683                         OnItemCommand (dlca);
684                         if (String.Compare (cn, CancelCommandName, true, inv) == 0) {
685                                 OnCancelCommand (dlca);
686                                 return true;
687                         } else if (String.Compare (cn, DeleteCommandName, true, inv) == 0) {
688                                 OnDeleteCommand (dlca);
689                                 return true;
690                         } else if (String.Compare (cn, EditCommandName, true, inv) == 0) {
691                                 OnEditCommand (dlca);
692                                 return true;
693                         } else if (String.Compare (cn, SelectCommandName, true, inv) == 0) {
694                                 OnSelectedIndexChanged (dlca);
695                                 return true;
696                         } else if (String.Compare (cn, UpdateCommandName, true, inv) == 0) {
697                                 OnUpdateCommand (dlca);
698                                 return true;
699                         }
700                         return false;
701                 }
702
703                 protected virtual void OnCancelCommand (DataListCommandEventArgs e)
704                 {
705                         DataListCommandEventHandler cancelCommand = (DataListCommandEventHandler) Events [cancelCommandEvent];
706                         if (cancelCommand != null)
707                                 cancelCommand (this, e);
708                 }
709
710                 protected virtual void OnDeleteCommand (DataListCommandEventArgs e)
711                 {
712                         DataListCommandEventHandler deleteCommand = (DataListCommandEventHandler) Events [deleteCommandEvent];
713                         if (deleteCommand != null)
714                                 deleteCommand (this, e);
715                 }
716
717                 protected virtual void OnEditCommand (DataListCommandEventArgs e)
718                 {
719                         DataListCommandEventHandler editCommand = (DataListCommandEventHandler) Events [editCommandEvent];
720                         if (editCommand != null)
721                                 editCommand (this, e);
722                 }
723 #if NET_2_0
724                 protected internal override void OnInit (EventArgs e)
725                 {
726                         // EditItemIndex and SelectedIndex now use the Control State (i.e not the View State)
727                         Page.RegisterRequiresControlState (this);
728                         base.OnInit (e);
729                 }
730 #endif
731                 protected virtual void OnItemCommand (DataListCommandEventArgs e)
732                 {
733                         DataListCommandEventHandler itemCommand = (DataListCommandEventHandler) Events [itemCommandEvent];
734                         if (itemCommand != null)
735                                 itemCommand (this, e);
736                 }
737
738                 protected virtual void OnItemCreated (DataListItemEventArgs e)
739                 {
740                         DataListItemEventHandler itemCreated = (DataListItemEventHandler) Events [itemCreatedEvent];
741                         if (itemCreated != null)
742                                 itemCreated (this, e);
743                 }
744
745                 protected virtual void OnItemDataBound (DataListItemEventArgs e)
746                 {
747                         DataListItemEventHandler itemDataBound = (DataListItemEventHandler) Events [itemDataBoundEvent];
748                         if (itemDataBound != null)
749                                 itemDataBound (this, e);
750                 }
751
752                 protected virtual void OnUpdateCommand (DataListCommandEventArgs e)
753                 {
754                         DataListCommandEventHandler updateCommand = (DataListCommandEventHandler) Events [updateCommandEvent];
755                         if (updateCommand != null)
756                                 updateCommand (this, e);
757                 }
758
759                 void ApplyControlStyle (Control ctrl, Style style)
760                 {
761                         if (style == null || false == ctrl.HasControls ())
762                                 return;
763
764                         foreach (Control c in ctrl.Controls) {
765                                 if (c is Table) {
766                                         Table tbl = (Table) c;
767                                         foreach (TableRow row in tbl.Rows)
768                                                 row.MergeStyle (style);
769                                 }
770                         }
771                 }
772
773                 protected override void PrepareControlHierarchy ()
774                 {
775                         if (!HasControls () || Controls.Count == 0)
776                                 return; // No one called CreateControlHierarchy() with DataSource != null
777
778                         Style alt = null;
779                         foreach (DataListItem item in Controls) {
780                                 switch (item.ItemType) {
781                                 case ListItemType.Item:
782                                         item.MergeStyle (itemStyle);
783                                         ApplyControlStyle (item, itemStyle);
784                                         break;
785                                 case ListItemType.AlternatingItem:
786                                         if (alt == null) {
787                                                 if (alternatingItemStyle != null) {
788                                                         alt = new TableItemStyle ();
789                                                         alt.CopyFrom (itemStyle);
790                                                         alt.CopyFrom (alternatingItemStyle);
791                                                 } else {
792                                                         alt = itemStyle;
793                                                 }
794                                         }
795
796                                         item.MergeStyle (alt);
797                                         ApplyControlStyle (item, alt);
798                                         break;
799                                 case ListItemType.EditItem:
800                                         if (editItemStyle != null) {
801                                                 item.MergeStyle (editItemStyle);
802                                                 ApplyControlStyle (item, editItemStyle);
803                                         } else {
804                                                 item.MergeStyle (itemStyle);
805                                                 ApplyControlStyle (item, itemStyle);
806                                         }
807                                         break;
808                                 case ListItemType.Footer:
809                                         if (!ShowFooter) {
810                                                 item.Visible = false;
811                                                 break;
812                                         }
813                                         if (footerStyle != null) {
814                                                 item.MergeStyle (footerStyle);
815                                                 ApplyControlStyle (item, footerStyle);
816                                         }
817                                         break;
818                                 case ListItemType.Header:
819                                         if (!ShowHeader) {
820                                                 item.Visible = false;
821                                                 break;
822                                         }
823                                         if (headerStyle != null) {
824                                                 item.MergeStyle (headerStyle);
825                                                 ApplyControlStyle (item, headerStyle);
826                                         }
827                                         break;
828                                 case ListItemType.SelectedItem:
829                                         if (selectedItemStyle != null) {
830                                                 item.MergeStyle (selectedItemStyle);
831                                                 ApplyControlStyle (item, selectedItemStyle);
832                                         } else {
833                                                 item.MergeStyle (itemStyle);
834                                                 ApplyControlStyle (item, itemStyle);
835                                         }
836                                         break;
837                                 case ListItemType.Separator:
838                                         if (separatorStyle != null) {
839                                                 item.MergeStyle(separatorStyle);
840                                                 ApplyControlStyle (item, separatorStyle);
841                                         }
842                                         else {
843                                                 item.MergeStyle (itemStyle);
844                                                 ApplyControlStyle (item, itemStyle);
845                                         }
846                                         break;
847                                 }
848                         }
849                 }
850
851 #if NET_2_0
852                 protected internal
853 #else           
854                 protected
855 #endif          
856                 override void RenderContents (HtmlTextWriter writer)
857                 {
858                         if (Items.Count == 0)
859                                 return;                 
860
861                         RepeatInfo ri = new RepeatInfo ();
862                         ri.RepeatColumns = RepeatColumns;
863                         ri.RepeatDirection = RepeatDirection;
864                         ri.RepeatLayout = RepeatLayout;
865                         ri.CaptionAlign = CaptionAlign;
866                         ri.Caption = Caption;
867                         ri.UseAccessibleHeader = UseAccessibleHeader;
868 /*
869 // debugging stuff that I prefer to keep for a while
870 Console.WriteLine ("RepeatColumns {0}", ri.RepeatColumns);
871 Console.WriteLine ("RepeatDirection {0}", ri.RepeatDirection);
872 Console.WriteLine ("RepeatLayout {0}", ri.RepeatLayout);
873 Console.WriteLine ("OuterTableImplied {0}", ExtractTemplateRows);
874 Console.WriteLine ("IRepeatInfoUser.HasFooter {0}", (ShowFooter && (footerTemplate != null)));
875 Console.WriteLine ("IRepeatInfoUser.HasHeader {0}", (ShowHeader && (headerTemplate != null)));
876 Console.WriteLine ("IRepeatInfoUser.HasSeparators {0}", (separatorTemplate != null));
877 Console.WriteLine ("IRepeatInfoUser.RepeatedItemCount {0}", Items.Count);
878 for (int i=0; i < Items.Count; i++) {
879         DataListItem dli = Items [i];
880         Console.WriteLine ("{0}: Index {1}, Type {2}", i, dli.ItemIndex, dli.ItemType);
881 }
882 */
883                         bool extract = ExtractTemplateRows;
884                         if (extract) {
885                                 ri.OuterTableImplied = true;
886                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
887                                 if (ControlStyleCreated) {
888                                         ControlStyle.AddAttributesToRender (writer);
889                                 }
890                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
891                                 ri.RenderRepeater (writer, this, ControlStyle, this);
892                                 writer.RenderEndTag ();
893                         } else {
894                                 ri.RenderRepeater (writer, this, ControlStyle, this);
895                         }
896                 }
897
898                 protected override object SaveViewState ()
899                 {
900 #if NET_2_0
901                         object[] state = new object [9];
902                         // FIXME: what's new in slot #0 ?
903                         state[8] = base.SaveViewState ();
904 #else
905                         object[] state = new object [8];
906                         state[0] = base.SaveViewState ();
907 #endif
908                         if (itemStyle != null)
909                                 state [1] = itemStyle.SaveViewState ();
910                         if (selectedItemStyle != null)
911                                 state [2] = selectedItemStyle.SaveViewState ();
912                         if (alternatingItemStyle != null)
913                                 state [3] = alternatingItemStyle.SaveViewState ();
914                         if (editItemStyle != null)
915                                 state [4] = editItemStyle.SaveViewState ();
916                         if (separatorStyle != null)
917                                 state [5] = separatorStyle.SaveViewState ();
918                         if (headerStyle != null)
919                                 state [6] = headerStyle.SaveViewState ();
920                         if (footerStyle != null)
921                                 state [7] = footerStyle.SaveViewState ();
922                         return state;
923                 }
924
925                 protected override void TrackViewState ()
926                 {
927                         base.TrackViewState ();
928                         if (alternatingItemStyle != null)
929                                 alternatingItemStyle.TrackViewState ();
930                         if (editItemStyle != null)
931                                 editItemStyle.TrackViewState ();
932                         if (footerStyle != null)
933                                 footerStyle.TrackViewState ();
934                         if (headerStyle != null)
935                                 headerStyle.TrackViewState ();
936                         if (itemStyle != null)
937                                 itemStyle.TrackViewState ();
938                         if (selectedItemStyle != null)
939                                 selectedItemStyle.TrackViewState ();
940                         if (separatorStyle != null)
941                                 separatorStyle.TrackViewState ();
942                 }
943
944
945                 [WebSysDescription ("")]
946                 [WebCategory ("Action")]
947                 public event DataListCommandEventHandler CancelCommand {
948                         add { Events.AddHandler (cancelCommandEvent, value); }
949                         remove { Events.RemoveHandler (cancelCommandEvent, value); }
950                 }
951
952                 [WebSysDescription ("")]
953                 [WebCategory ("Action")]
954                 public event DataListCommandEventHandler DeleteCommand {
955                         add { Events.AddHandler (deleteCommandEvent, value); }
956                         remove { Events.RemoveHandler (deleteCommandEvent, value); }
957                 }
958
959                 [WebSysDescription ("")]
960                 [WebCategory ("Action")]
961                 public event DataListCommandEventHandler EditCommand {
962                         add { Events.AddHandler (editCommandEvent, value); }
963                         remove { Events.RemoveHandler (editCommandEvent, value); }
964                 }
965
966                 [WebSysDescription ("")]
967                 [WebCategory ("Action")]
968                 public event DataListCommandEventHandler ItemCommand {
969                         add { Events.AddHandler (itemCommandEvent, value); }
970                         remove { Events.RemoveHandler (itemCommandEvent, value); }
971                 }
972
973                 [WebSysDescription ("")]
974                 [WebCategory ("Action")]
975                 public event DataListItemEventHandler ItemCreated {
976                         add { Events.AddHandler (itemCreatedEvent, value); }
977                         remove { Events.RemoveHandler (itemCreatedEvent, value); }
978                 }
979
980                 [WebSysDescription ("")]
981                 [WebCategory ("Action")]
982                 public event DataListItemEventHandler ItemDataBound {
983                         add { Events.AddHandler (itemDataBoundEvent, value); }
984                         remove { Events.RemoveHandler (itemDataBoundEvent, value); }
985                 }
986
987                 [WebSysDescription ("")]
988                 [WebCategory ("Action")]
989                 public event DataListCommandEventHandler UpdateCommand {
990                         add { Events.AddHandler (updateCommandEvent, value); }
991                         remove { Events.RemoveHandler (updateCommandEvent, value); }
992                 }
993
994
995                 // IRepeatInfoUser support
996
997                 bool IRepeatInfoUser.HasFooter {
998                         get { return (ShowFooter && (footerTemplate != null)); }
999                 }
1000
1001                 bool IRepeatInfoUser.HasHeader {
1002                         get { return (ShowHeader && (headerTemplate != null)); }
1003                 }
1004                 
1005                 bool IRepeatInfoUser.HasSeparators {
1006                         get { return (separatorTemplate != null); }
1007                 }
1008
1009                 // don't include header, footer and separators in the count
1010                 int IRepeatInfoUser.RepeatedItemCount {
1011                         get {
1012                                 if (idx == -1) {
1013                                         object o = ViewState ["Items"];
1014                                         idx = (o == null) ? 0 : (int) o;
1015                                 }
1016                                 return idx;
1017                         }
1018                 }
1019
1020                 Style IRepeatInfoUser.GetItemStyle (ListItemType itemType, int repeatIndex)
1021                 {
1022                         DataListItem item = null;
1023                         switch (itemType) {
1024                         case ListItemType.Header:
1025                         case ListItemType.Footer:
1026                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1027                                         throw new ArgumentOutOfRangeException ();
1028
1029                                 item = FindFirstItem (itemType);
1030                                 break;
1031                         case ListItemType.Item:
1032                         case ListItemType.AlternatingItem:
1033                         case ListItemType.SelectedItem:
1034                         case ListItemType.EditItem:
1035                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1036                                         throw new ArgumentOutOfRangeException ();
1037
1038                                 item = FindBestItem (repeatIndex);
1039                                 break;
1040                         case ListItemType.Separator:
1041                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1042                                         throw new ArgumentOutOfRangeException ();
1043
1044                                 item = FindSpecificItem (itemType, repeatIndex);
1045                                 break;
1046                         default:
1047                                 item = null;
1048                                 break;
1049                         }
1050
1051                         if (item == null || item.ControlStyleCreated == false)
1052                                 return null;
1053
1054                         return item.ControlStyle;
1055                 }
1056
1057                 // Header and Footer don't have a "real" index (-1)
1058                 private DataListItem FindFirstItem (ListItemType itemType)
1059                 {
1060                         for (int i = 0; i < Controls.Count; i++) {
1061                                 DataListItem item = (Controls [i] as DataListItem);
1062                                 if ((item != null) && (item.ItemType == itemType))
1063                                         return item;
1064                         }
1065                         return null;
1066                 }
1067
1068                 // Both Type and Index must match (e.g. Separator)
1069                 private DataListItem FindSpecificItem (ListItemType itemType, int repeatIndex)
1070                 {
1071                         for (int i = 0; i < Controls.Count; i++) {
1072                                 DataListItem item = (Controls [i] as DataListItem);
1073                                 if ((item != null) && (item.ItemType == itemType) && (item.ItemIndex == repeatIndex))
1074                                         return item;
1075                         }
1076                         return null;
1077                 }
1078
1079                 // we get call for Item even for AlternatingItem :(
1080                 private DataListItem FindBestItem (int repeatIndex)
1081                 {
1082                         for (int i = 0; i < Controls.Count; i++) {
1083                                 DataListItem item = (Controls [i] as DataListItem);
1084                                 if ((item != null) && (item.ItemIndex == repeatIndex)) {
1085                                         switch (item.ItemType) {
1086                                         case ListItemType.Item:
1087                                         case ListItemType.AlternatingItem:
1088                                         case ListItemType.SelectedItem:
1089                                         case ListItemType.EditItem:
1090                                                 return item;
1091                                         default:
1092                                                 return null;
1093                                         }
1094                                 }
1095                         }
1096                         return null;
1097                 }
1098
1099                 void IRepeatInfoUser.RenderItem (ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
1100                 {
1101                         // if possible take the easy way out...
1102                         if (!HasControls ())
1103                                 return;
1104
1105                         DataListItem item = null;
1106                         switch (itemType) {
1107                         case ListItemType.Header:
1108                         case ListItemType.Footer:
1109                                 item = FindFirstItem (itemType);
1110                                 break;
1111                         case ListItemType.Item:
1112                         case ListItemType.AlternatingItem:
1113                         case ListItemType.SelectedItem:
1114                         case ListItemType.EditItem:
1115                                 item = FindBestItem (repeatIndex);
1116                                 break;
1117                         case ListItemType.Separator:
1118                                 item = FindSpecificItem (itemType, repeatIndex);
1119                                 break;
1120                         }
1121
1122                         if (item != null) {
1123                                 bool extract = ExtractTemplateRows;
1124                                 bool table = (RepeatLayout == RepeatLayout.Table);
1125                                 if (!table || extract) {
1126                                         // sadly RepeatInfo doesn't support Style for RepeatLayout.Flow
1127                                         Style s = (this as IRepeatInfoUser).GetItemStyle (itemType, repeatIndex);
1128                                         if (s != null)
1129                                                 item.ControlStyle.CopyFrom (s);
1130                                 }
1131 //Console.WriteLine ("RenderItem #{0} type {1}", repeatIndex, itemType);
1132                                 item.RenderItem (writer, extract, table);
1133                         } else {
1134 //Console.WriteLine ("Couldn't find #{0} type {1} out of {2} items / {3} controls", repeatIndex, itemType, Items.Count, Controls.Count);
1135                         }
1136                 }
1137         }
1138 }