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