Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / UI / WebControls / DetailsView.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DetailsView.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.UI.WebControls {
8
9     using System;
10     using System.Collections;
11     using System.Collections.Specialized;
12     using System.ComponentModel;
13     using System.ComponentModel.Design;
14     using System.Drawing.Design;
15     using System.Globalization;
16     using System.IO;
17     using System.Reflection;
18     using System.Security.Permissions;
19     using System.Text;
20     using System.Web.UI.Adapters;
21     using System.Web.Util;
22     using System.Web.UI.WebControls.Adapters;
23     using System.Diagnostics.CodeAnalysis;
24     using System.Web.Security.Cryptography;
25
26     /// <devdoc>
27     ///    <para>
28     ///       Displays a data record from a data source in a table layout. The data source
29     ///       is any object that implements IEnumerable or IListSource, which includes ADO.NET data,
30     ///       arrays, ArrayLists, DataSourceControl, etc.
31     ///    </para>
32     /// </devdoc>
33     [
34     Designer("System.Web.UI.Design.WebControls.DetailsViewDesigner, " + AssemblyRef.SystemDesign),
35     ControlValueProperty("SelectedValue"),
36     DefaultEvent("PageIndexChanging"),
37     ToolboxData("<{0}:DetailsView runat=\"server\" Width=\"125px\" Height=\"50px\"></{0}:DetailsView>"),
38     SupportsEventValidation
39     ]
40     [DataKeyProperty("DataKey")]
41     public class DetailsView : CompositeDataBoundControl, IDataItemContainer, ICallbackContainer, ICallbackEventHandler, IPostBackEventHandler, IPostBackContainer, IDataBoundItemControl, IFieldControl {
42
43         private static readonly object EventItemCommand = new object();
44         private static readonly object EventItemCreated = new object();
45         private static readonly object EventItemDeleted = new object();
46         private static readonly object EventItemDeleting = new object();
47         private static readonly object EventItemInserting = new object();
48         private static readonly object EventItemInserted = new object();
49         private static readonly object EventItemUpdating = new object();
50         private static readonly object EventItemUpdated = new object();
51         private static readonly object EventModeChanged = new object();
52         private static readonly object EventModeChanging = new object();
53         private static readonly object EventPageIndexChanged = new object();
54         private static readonly object EventPageIndexChanging = new object();
55
56         private ITemplate _headerTemplate;
57         private ITemplate _footerTemplate;
58         private ITemplate _pagerTemplate;
59         private ITemplate _emptyDataTemplate;
60
61         private TableItemStyle _rowStyle;
62         private TableItemStyle _headerStyle;
63         private TableItemStyle _footerStyle;
64         private TableItemStyle _editRowStyle;
65         private TableItemStyle _alternatingRowStyle;
66         private TableItemStyle _commandRowStyle;
67         private TableItemStyle _insertRowStyle;
68         private TableItemStyle _emptyDataRowStyle;
69         private TableItemStyle _fieldHeaderStyle;
70
71         private DetailsViewRow _bottomPagerRow;
72         private DetailsViewRow _footerRow;
73         private DetailsViewRow _headerRow;
74         private DetailsViewRow _topPagerRow;
75
76         private TableItemStyle _pagerStyle;
77         private PagerSettings _pagerSettings;
78
79         private ArrayList _rowsArray;
80         private DataControlFieldCollection _fieldCollection;
81         private DetailsViewRowCollection _rowsCollection;
82         private int _pageCount;
83         private object _dataItem;
84         private int _dataItemIndex;
85         private OrderedDictionary _boundFieldValues;
86         private DataKey _dataKey;
87         private OrderedDictionary _keyTable;
88         private string[] _dataKeyNames;
89
90         private int _pageIndex;
91         private DetailsViewMode _defaultMode = DetailsViewMode.ReadOnly;
92         private DetailsViewMode _mode;
93         private bool _modeSet;
94         private bool _useServerPaging;
95         private string _modelValidationGroup;
96
97         private bool _renderClientScript;
98         private bool _renderClientScriptValid = false;
99
100         private IAutoFieldGenerator _rowsGenerator;
101         private DetailsViewRowsGenerator _defaultRowsGenerator = new DetailsViewRowsGenerator();
102
103         private IOrderedDictionary _deleteKeys;
104         private IOrderedDictionary _deleteValues;
105         private IOrderedDictionary _insertValues;
106         private IOrderedDictionary _updateKeys;
107         private IOrderedDictionary _updateOldValues;
108         private IOrderedDictionary _updateNewValues;
109
110         /// <summary>
111         /// The name of the method on the page which is called when this Control does an update operation.
112         /// </summary>
113         [
114         DefaultValue(""),
115         Themeable(false),
116         WebCategory("Data"),
117         WebSysDescription(SR.DataBoundControl_UpdateMethod)
118         ]
119         public new virtual string UpdateMethod {
120             get {
121                 return base.UpdateMethod;
122             }
123             set {
124                 base.UpdateMethod = value;
125             }
126         }
127
128         /// <summary>
129         /// The name of the method on the page which is called when this Control does a delete operation.
130         /// </summary>
131         [
132         DefaultValue(""),
133         Themeable(false),
134         WebCategory("Data"),
135         WebSysDescription(SR.DataBoundControl_DeleteMethod)
136         ]
137         public new virtual string DeleteMethod {
138             get {
139                 return base.DeleteMethod;
140             }
141             set {
142                 base.DeleteMethod = value;
143             }
144         }
145
146         /// <summary>
147         /// The name of the method on the page which is called when this Control does an insert operation.
148         /// </summary>
149         [
150         DefaultValue(""),
151         Themeable(false),
152         WebCategory("Data"),
153         WebSysDescription(SR.DataBoundControl_InsertMethod)
154         ]
155         public new virtual string InsertMethod {
156             get {
157                 return base.InsertMethod;
158             }
159             set {
160                 base.InsertMethod = value;
161             }
162         }
163
164         /// <devdoc>
165         /// <para>Gets or sets a value that indicates whether paging is allowed.</para>
166         /// </devdoc>
167         [
168         WebCategory("Paging"),
169         DefaultValue(false),
170         WebSysDescription(SR.DetailsView_AllowPaging)
171         ]
172         public virtual bool AllowPaging {
173             get {
174                 object o = ViewState["AllowPaging"];
175                 if (o != null)
176                     return(bool)o;
177                 return false;
178             }
179             set {
180                 bool oldValue = AllowPaging;
181                 if (value != oldValue) {
182                     ViewState["AllowPaging"] = value;
183                     if (Initialized) {
184                         RequiresDataBinding = true;
185                     }
186                 }
187             }
188         }
189
190
191         /// <devdoc>
192         /// <para>Indicates the style properties of alternating rows.</para>
193         /// </devdoc>
194         [
195         WebCategory("Styles"),
196         DefaultValue(null),
197         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
198         NotifyParentProperty(true),
199         PersistenceMode(PersistenceMode.InnerProperty),
200         WebSysDescription(SR.DetailsView_AlternatingRowStyle)
201         ]
202         public TableItemStyle AlternatingRowStyle {
203             get {
204                 if (_alternatingRowStyle == null) {
205                     _alternatingRowStyle = new TableItemStyle();
206                     if (IsTrackingViewState)
207                         ((IStateManager)_alternatingRowStyle).TrackViewState();
208                 }
209                 return _alternatingRowStyle;
210             }
211         }
212
213
214         /// <devdoc>
215         /// <para>Gets or sets a value that indicates whether a button field for deleting will automatically
216         /// be created.</para>
217         /// </devdoc>
218         [
219         WebCategory("Behavior"),
220         DefaultValue(false),
221         WebSysDescription(SR.DetailsView_AutoGenerateDeleteButton)
222         ]
223         public virtual bool AutoGenerateDeleteButton {
224             get {
225                 object o = ViewState["AutoGenerateDeleteButton"];
226                 if (o != null)
227                     return(bool)o;
228                 return false;
229             }
230             set {
231                 bool oldValue = AutoGenerateDeleteButton;
232                 if (value != oldValue) {
233                     ViewState["AutoGenerateDeleteButton"] = value;
234                     if (Initialized) {
235                         RequiresDataBinding = true;
236                     }
237                 }
238             }
239         }
240
241
242         /// <devdoc>
243         /// <para>Gets or sets a value that indicates whether an edit field will automatically
244         /// be created.</para>
245         /// </devdoc>
246         [
247         WebCategory("Behavior"),
248         DefaultValue(false),
249         WebSysDescription(SR.DetailsView_AutoGenerateEditButton)
250         ]
251         public virtual bool AutoGenerateEditButton {
252             get {
253                 object o = ViewState["AutoGenerateEditButton"];
254                 if (o != null)
255                     return(bool)o;
256                 return false;
257             }
258             set {
259                 bool oldValue = AutoGenerateEditButton;
260                 if (value != oldValue) {
261                     ViewState["AutoGenerateEditButton"] = value;
262                     if (Initialized) {
263                         RequiresDataBinding = true;
264                     }
265                 }
266             }
267         }
268
269
270         /// <devdoc>
271         /// <para>Gets or sets a value that indicates whether an insert field will automatically
272         /// be created.</para>
273         /// </devdoc>
274         [
275         WebCategory("Behavior"),
276         DefaultValue(false),
277         WebSysDescription(SR.DetailsView_AutoGenerateInsertButton)
278         ]
279         public virtual bool AutoGenerateInsertButton {
280             get {
281                 object o = ViewState["AutoGenerateInsertButton"];
282                 if (o != null)
283                     return(bool)o;
284                 return false;
285             }
286             set {
287                 bool oldValue = AutoGenerateInsertButton;
288                 if (value != oldValue) {
289                     ViewState["AutoGenerateInsertButton"] = value;
290                     if (Initialized) {
291                         RequiresDataBinding = true;
292                     }
293                 }
294             }
295         }
296
297
298         /// <devdoc>
299         /// <para>Gets or sets a value that indicates whether fields will automatically
300         /// be created for each bound data field.</para>
301         /// </devdoc>
302         [
303         WebCategory("Behavior"),
304         DefaultValue(true),
305         WebSysDescription(SR.DetailsView_AutoGenerateRows)
306         ]
307         public virtual bool AutoGenerateRows {
308             get {
309                 object o = ViewState["AutoGenerateRows"];
310                 if (o != null)
311                     return(bool)o;
312                 return true;
313             }
314             set {
315                 bool oldValue = AutoGenerateRows;
316                 if (value != oldValue) {
317                     ViewState["AutoGenerateRows"] = value;
318                     if (Initialized) {
319                         RequiresDataBinding = true;
320                     }
321                 }
322             }
323         }
324
325
326         /// <devdoc>
327         /// <para>Gets or sets the URL of an image to display in the
328         /// background of the <see cref='System.Web.UI.WebControls.DetailsView'/>.</para>
329         /// </devdoc>
330         [
331         WebCategory("Appearance"),
332         DefaultValue(""),
333         Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
334         UrlProperty(),
335         WebSysDescription(SR.WebControl_BackImageUrl)
336         ]
337         public virtual string BackImageUrl {
338             get {
339                 if (ControlStyleCreated == false) {
340                     return String.Empty;
341                 }
342                 return((TableStyle)ControlStyle).BackImageUrl;
343             }
344             set {
345                 ((TableStyle)ControlStyle).BackImageUrl = value;
346             }
347         }
348
349
350         [
351         Browsable(false),
352         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
353         ]
354         public virtual DetailsViewRow BottomPagerRow {
355             get {
356                 if (_bottomPagerRow == null) {
357                     EnsureChildControls();
358                 }
359                 return _bottomPagerRow;
360             }
361         }
362
363         private IOrderedDictionary BoundFieldValues {
364             get {
365                 if (_boundFieldValues == null) {
366                     int capacity = Fields.Count;
367                     if (AutoGenerateRows) {
368                         capacity += 10;
369                     }
370                     _boundFieldValues = new OrderedDictionary(capacity);
371                 }
372                 return _boundFieldValues;
373             }
374         }
375
376
377         [
378         Localizable(true),
379         DefaultValue(""),
380         WebCategory("Accessibility"),
381         WebSysDescription(SR.DataControls_Caption)
382         ]
383         public virtual string Caption {
384             get {
385                 string s = (string)ViewState["Caption"];
386                 return (s != null) ? s : String.Empty;
387             }
388             set {
389                 ViewState["Caption"] = value;
390             }
391         }
392
393
394         [
395         DefaultValue(TableCaptionAlign.NotSet),
396         WebCategory("Accessibility"),
397         WebSysDescription(SR.WebControl_CaptionAlign)
398         ]
399         public virtual TableCaptionAlign CaptionAlign {
400             get {
401                 object o = ViewState["CaptionAlign"];
402                 return (o != null) ? (TableCaptionAlign)o : TableCaptionAlign.NotSet;
403             }
404             set {
405                 if ((value < TableCaptionAlign.NotSet) ||
406                     (value > TableCaptionAlign.Right)) {
407                     throw new ArgumentOutOfRangeException("value");
408                 }
409                 ViewState["CaptionAlign"] = value;
410             }
411         }
412
413
414
415         /// <devdoc>
416         /// <para>Indicates the amount of space between cells.</para>
417         /// </devdoc>
418         [
419         WebCategory("Layout"),
420         DefaultValue(-1),
421         WebSysDescription(SR.DetailsView_CellPadding)
422         ]
423         public virtual int CellPadding {
424             get {
425                 if (ControlStyleCreated == false) {
426                     return -1;
427                 }
428                 return((TableStyle)ControlStyle).CellPadding;
429             }
430             set {
431                 ((TableStyle)ControlStyle).CellPadding = value;
432             }
433         }
434
435
436         /// <devdoc>
437         /// <para>Gets or sets the amount of space between the contents of
438         /// a cell and the cell's border.</para>
439         /// </devdoc>
440         [
441         WebCategory("Layout"),
442         DefaultValue(0),
443         WebSysDescription(SR.DetailsView_CellSpacing)
444         ]
445         public virtual int CellSpacing {
446             get {
447                 if (ControlStyleCreated == false) {
448                     return 0;
449                 }
450                 return((TableStyle)ControlStyle).CellSpacing;
451             }
452             set {
453                 ((TableStyle)ControlStyle).CellSpacing = value;
454             }
455         }
456
457
458         /// <devdoc>
459         /// <para>Indicates the style properties of command rows.</para>
460         /// </devdoc>
461         [
462         WebCategory("Styles"),
463         DefaultValue(null),
464         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
465         NotifyParentProperty(true),
466         PersistenceMode(PersistenceMode.InnerProperty),
467         WebSysDescription(SR.DetailsView_CommandRowStyle)
468         ]
469         public TableItemStyle CommandRowStyle {
470             get {
471                 if (_commandRowStyle == null) {
472                     _commandRowStyle = new TableItemStyle();
473                     if (IsTrackingViewState)
474                         ((IStateManager)_commandRowStyle).TrackViewState();
475                 }
476                 return _commandRowStyle;
477             }
478         }
479
480
481         [
482         Browsable(false),
483         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
484         ]
485         public DetailsViewMode CurrentMode {
486             get {
487                 return Mode;
488             }
489         }
490
491         // implement this publicly so DataBinder.Eval(container.DataItem, "x") still works.
492         [
493         Browsable(false),
494         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
495         ]
496         public virtual object DataItem {
497             get {
498                 if (CurrentMode == DetailsViewMode.Insert) {
499                     return null;
500                 }
501                 return _dataItem;
502             }
503         }
504
505         [
506         Browsable(false),
507         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
508         ]
509         public int DataItemCount {
510             get {
511                 return PageCount;
512             }
513         }
514
515         [
516         Browsable(false),
517         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
518         ]
519         public virtual int DataItemIndex {
520             get {
521                 if (CurrentMode == DetailsViewMode.Insert) {
522                     return -1;
523                 }
524                 return _dataItemIndex;
525             }
526         }
527
528
529         [
530         DefaultValue(null),
531         Editor("System.Web.UI.Design.WebControls.DataFieldEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
532         TypeConverterAttribute(typeof(StringArrayConverter)),
533         WebCategory("Data"),
534         WebSysDescription(SR.DataControls_DataKeyNames)
535         ]
536         public virtual string[] DataKeyNames {
537             get {
538                 object o = _dataKeyNames;
539                 if (o != null) {
540                     return(string[])((string[])o).Clone();
541                 }
542                 return new string[0];
543             }
544             set {
545                 if (!DataBoundControlHelper.CompareStringArrays(value, DataKeyNamesInternal)) {
546                     if (value != null) {
547                         _dataKeyNames = (string[])value.Clone();
548                     } 
549                     else {
550                         _dataKeyNames = null;
551                     }
552
553                     _keyTable = null;
554                     if (Initialized) {
555                         RequiresDataBinding = true;
556                     }
557                 }
558             }
559         }
560
561         // This version doesn't clone the array
562         private string[] DataKeyNamesInternal {
563             get {
564                 object o = _dataKeyNames;
565                 if (o != null) {
566                     return (string[])o;
567                 }
568                 return new string[0];
569             }
570         }
571
572         /// <devdoc>
573         /// </devdoc>
574         [
575         Browsable(false),
576         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
577         WebSysDescription(SR.DetailsView_DataKey)
578         ]
579         public virtual DataKey DataKey {
580             get {
581                 if (_dataKey == null) {
582                     _dataKey = new DataKey(KeyTable);
583                 }
584                 return _dataKey;
585             }
586         }
587
588
589         [
590         WebCategory("Behavior"),
591         DefaultValue(DetailsViewMode.ReadOnly),
592         WebSysDescription(SR.View_DefaultMode)
593         ]
594         public virtual DetailsViewMode DefaultMode {
595             get {
596                 return _defaultMode;
597             }
598             set {
599                 if (value < DetailsViewMode.ReadOnly || value > DetailsViewMode.Insert) {
600                     throw new ArgumentOutOfRangeException("value");
601                 }
602                 _defaultMode = value;
603             }
604         }
605
606
607         /// <devdoc>
608         /// <para>Indicates the style properties of each row when in edit mode.</para>
609         /// </devdoc>
610         [
611         WebCategory("Styles"),
612         DefaultValue(null),
613         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
614         NotifyParentProperty(true),
615         PersistenceMode(PersistenceMode.InnerProperty),
616         WebSysDescription(SR.View_EditRowStyle)
617         ]
618         public TableItemStyle EditRowStyle {
619             get {
620                 if (_editRowStyle == null) {
621                     _editRowStyle = new TableItemStyle();
622                     if (IsTrackingViewState)
623                         ((IStateManager)_editRowStyle).TrackViewState();
624                 }
625                 return _editRowStyle;
626             }
627         }
628
629
630         /// <devdoc>
631         /// <para>Indicates the style properties of null rows.</para>
632         /// </devdoc>
633         [
634         WebCategory("Styles"),
635         DefaultValue(null),
636         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
637         NotifyParentProperty(true),
638         PersistenceMode(PersistenceMode.InnerProperty),
639         WebSysDescription(SR.View_EmptyDataRowStyle)
640         ]
641         public TableItemStyle EmptyDataRowStyle {
642             get {
643                 if (_emptyDataRowStyle == null) {
644                     _emptyDataRowStyle = new TableItemStyle();
645                     if (IsTrackingViewState)
646                         ((IStateManager)_emptyDataRowStyle).TrackViewState();
647                 }
648                 return _emptyDataRowStyle;
649             }
650         }
651
652
653         /// <devdoc>
654         /// <para>Indicates the template to use when no records are returned from the datasource within the DetailsView.
655         /// </devdoc>
656         [
657         Browsable(false),
658         DefaultValue(null),
659         PersistenceMode(PersistenceMode.InnerProperty),
660         TemplateContainer(typeof(DetailsView)),
661         WebSysDescription(SR.View_EmptyDataTemplate)
662         ]
663         public virtual ITemplate EmptyDataTemplate {
664             get {
665                 return _emptyDataTemplate;
666             }
667             set {
668                 _emptyDataTemplate = value;
669             }
670         }
671
672
673         /// <devdoc>
674         /// <para>The header text displayed if no EmptyDataTemplate is defined.
675         /// </devdoc>
676         [
677         Localizable(true),
678         WebCategory("Appearance"),
679         DefaultValue(""),
680         WebSysDescription(SR.View_EmptyDataText),
681         ]
682         public virtual String EmptyDataText {
683             get {
684                 object o = ViewState["EmptyDataText"];
685                 if (o != null) {
686                     return (string)o;
687                 }
688                 return String.Empty;
689             }
690             set {
691                 ViewState["EmptyDataText"] = value;
692             }
693         }
694
695         [
696         WebCategory("Behavior"),
697         DefaultValue(true),
698         WebSysDescription(SR.DataBoundControl_EnableModelValidation)
699         ]
700         public virtual bool EnableModelValidation {
701             get {
702                 object o = ViewState["EnableModelValidation"];
703                 if (o != null) {
704                     return (bool)o;
705                 }
706                 return true;
707             }
708             set {
709                 ViewState["EnableModelValidation"] = value;
710             }
711         }
712
713         [
714         WebCategory("Behavior"),
715         DefaultValue(false),
716         WebSysDescription(SR.DetailsView_EnablePagingCallbacks)
717         ]
718         public virtual bool EnablePagingCallbacks {
719             get {
720                 object o = ViewState["EnablePagingCallbacks"];
721                 if (o != null) {
722                     return (bool)o;
723                 }
724                 return false;
725             }
726             set {
727                 ViewState["EnablePagingCallbacks"] = value;
728             }
729         }
730
731
732         /// <devdoc>
733         /// <para>Indicates the style properties of the header column.</para>
734         /// </devdoc>
735         [
736         WebCategory("Styles"),
737         DefaultValue(null),
738         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
739         NotifyParentProperty(true),
740         PersistenceMode(PersistenceMode.InnerProperty),
741         WebSysDescription(SR.DetailsView_FieldHeaderStyle)
742         ]
743         public TableItemStyle FieldHeaderStyle {
744             get {
745                 if (_fieldHeaderStyle == null) {
746                     _fieldHeaderStyle = new TableItemStyle();
747                     if (IsTrackingViewState)
748                         ((IStateManager)_fieldHeaderStyle).TrackViewState();
749                 }
750                 return _fieldHeaderStyle;
751             }
752         }
753
754
755         /// <devdoc>
756         /// <para>Gets a collection of <see cref='System.Web.UI.WebControls.DataControlField'/> controls in the <see cref='System.Web.UI.WebControls.DetailsView'/>. This property is read-only.</para>
757         /// </devdoc>
758         [
759         DefaultValue(null),
760         Editor("System.Web.UI.Design.WebControls.DataControlFieldTypeEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
761         MergableProperty(false),
762         PersistenceMode(PersistenceMode.InnerProperty),
763         WebCategory("Default"),
764         WebSysDescription(SR.DetailsView_Fields)
765         ]
766         public virtual DataControlFieldCollection Fields {
767             get {
768                 if (_fieldCollection == null) {
769                     _fieldCollection = new DataControlFieldCollection();
770                     _fieldCollection.FieldsChanged += new EventHandler(OnFieldsChanged);
771                     if (IsTrackingViewState)
772                         ((IStateManager)_fieldCollection).TrackViewState();
773                 }
774                 return _fieldCollection;
775             }
776         }
777         
778         private int FirstDisplayedPageIndex {
779             get {
780                 object o = ViewState["FirstDisplayedPageIndex"];
781                 if (o != null) {
782                     return (int)o;
783                 }
784                 return -1;
785             }
786             set {
787                 ViewState["FirstDisplayedPageIndex"] = value;
788             }
789         }
790
791
792         [
793         Browsable(false),
794         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
795         ]
796         public virtual DetailsViewRow FooterRow {
797             get {
798                 if (_footerRow == null) {
799                     EnsureChildControls();
800                 }
801                 return _footerRow;
802             }
803         }
804
805
806         /// <devdoc>
807         /// <para>Indicates the style properties of the footer row.</para>
808         /// </devdoc>
809         [
810         WebCategory("Styles"),
811         DefaultValue(null),
812         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
813         NotifyParentProperty(true),
814         PersistenceMode(PersistenceMode.InnerProperty),
815         WebSysDescription(SR.DetailsView_FooterStyle)
816         ]
817         public TableItemStyle FooterStyle {
818             get {
819                 if (_footerStyle == null) {
820                     _footerStyle = new TableItemStyle();
821                     if (IsTrackingViewState)
822                         ((IStateManager)_footerStyle).TrackViewState();
823                 }
824                 return _footerStyle;
825             }
826         }
827
828
829         /// <devdoc>
830         /// <para>Indicates the template to use for a footer item within the DetailsView.
831         /// </devdoc>
832         [
833         Browsable(false),
834         DefaultValue(null),
835         PersistenceMode(PersistenceMode.InnerProperty),
836         TemplateContainer(typeof(DetailsView)),
837         WebSysDescription(SR.DetailsView_FooterTemplate)
838         ]
839         public virtual ITemplate FooterTemplate {
840             get {
841                 return _footerTemplate;
842             }
843             set {
844                 _footerTemplate = value;
845             }
846         }
847
848
849         /// <devdoc>
850         /// <para>The header text displayed if no FooterTemplate is defined.
851         /// </devdoc>
852         [
853         Localizable(true),
854         WebCategory("Appearance"),
855         DefaultValue(""),
856         WebSysDescription(SR.View_FooterText),
857         ]
858         public virtual String FooterText {
859             get {
860                 object o = ViewState["FooterText"];
861                 if (o != null) {
862                     return (string)o;
863                 }
864                 return String.Empty;
865             }
866             set {
867                 ViewState["FooterText"] = value;
868             }
869         }
870
871
872         /// <devdoc>
873         /// <para>Gets or sets a value that specifies the grid line style.</para>
874         /// </devdoc>
875         [
876         WebCategory("Appearance"),
877         DefaultValue(GridLines.Both),
878         WebSysDescription(SR.DataControls_GridLines)
879         ]
880         public virtual GridLines GridLines {
881             get {
882                 if (ControlStyleCreated == false) {
883                     return GridLines.Both;
884                 }
885                 return((TableStyle)ControlStyle).GridLines;
886             }
887             set {
888                 ((TableStyle)ControlStyle).GridLines = value;
889             }
890         }
891
892
893         [
894         Browsable(false),
895         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
896         ]
897         public virtual DetailsViewRow HeaderRow {
898             get {
899                 if (_headerRow == null) {
900                     EnsureChildControls();
901                 }
902                 return _headerRow;
903             }
904         }
905
906
907         /// <devdoc>
908         /// <para>Indicates the style properties of the header row.</para>
909         /// </devdoc>
910         [
911         WebCategory("Styles"),
912         DefaultValue(null),
913         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
914         NotifyParentProperty(true),
915         PersistenceMode(PersistenceMode.InnerProperty),
916         WebSysDescription(SR.WebControl_HeaderStyle)
917         ]
918         public TableItemStyle HeaderStyle {
919             get {
920                 if (_headerStyle == null) {
921                     _headerStyle = new TableItemStyle();
922                     if (IsTrackingViewState)
923                         ((IStateManager)_headerStyle).TrackViewState();
924                 }
925                 return _headerStyle;
926             }
927         }
928
929
930         /// <devdoc>
931         /// <para>Indicates the template to use for a header item within the DetailsView.
932         /// </devdoc>
933         [
934         Browsable(false),
935         DefaultValue(null),
936         PersistenceMode(PersistenceMode.InnerProperty),
937         TemplateContainer(typeof(DetailsView)),
938         WebSysDescription(SR.WebControl_HeaderTemplate)
939         ]
940         public virtual ITemplate HeaderTemplate {
941             get {
942                 return _headerTemplate;
943             }
944             set {
945                 _headerTemplate = value;
946             }
947         }
948
949
950         /// <devdoc>
951         /// <para>The header text displayed if no HeaderTemplate is defined.
952         /// </devdoc>
953         [
954         Localizable(true),
955         WebCategory("Appearance"),
956         DefaultValue(""),
957         WebSysDescription(SR.View_HeaderText),
958         ]
959         public virtual String HeaderText {
960             get {
961                 object o = ViewState["HeaderText"];
962                 if (o != null) {
963                     return (string)o;
964                 }
965                 return String.Empty;
966             }
967             set {
968                 ViewState["HeaderText"] = value;
969             }
970         }
971
972
973         /// <devdoc>
974         /// <para>Gets or sets a value that specifies the alignment of a rows with respect
975         /// surrounding text.</para>
976         /// </devdoc>
977         [
978         Category("Layout"),
979         DefaultValue(HorizontalAlign.NotSet),
980         WebSysDescription(SR.WebControl_HorizontalAlign)
981         ]
982         public virtual HorizontalAlign HorizontalAlign {
983             get {
984                 if (ControlStyleCreated == false) {
985                     return HorizontalAlign.NotSet;
986                 }
987                 return((TableStyle)ControlStyle).HorizontalAlign;
988             }
989             set {
990                 ((TableStyle)ControlStyle).HorizontalAlign = value;
991             }
992         }
993
994
995         /// <devdoc>
996         /// <para>Indicates the style properties of each row when in insert mode.</para>
997         /// </devdoc>
998         [
999         WebCategory("Styles"),
1000         DefaultValue(null),
1001         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1002         NotifyParentProperty(true),
1003         PersistenceMode(PersistenceMode.InnerProperty),
1004         WebSysDescription(SR.View_InsertRowStyle)
1005         ]
1006         public TableItemStyle InsertRowStyle {
1007             get {
1008                 if (_insertRowStyle == null) {
1009                     _insertRowStyle = new TableItemStyle();
1010                     if (IsTrackingViewState)
1011                         ((IStateManager)_insertRowStyle).TrackViewState();
1012                 }
1013                 return _insertRowStyle;
1014             }
1015         }
1016
1017         private OrderedDictionary KeyTable {
1018             get {
1019                 if (_keyTable == null) {
1020                     _keyTable = new OrderedDictionary(DataKeyNamesInternal.Length);
1021                 }
1022                 return _keyTable;
1023             }
1024         }
1025
1026
1027         private DetailsViewMode Mode {
1028             get {
1029                 // if the mode wasn't explicitly set by LoadControlState or by the user, the mode is the DefaultMode.
1030                 if (!_modeSet || DesignMode) {
1031                     _mode = DefaultMode;
1032                     _modeSet = true;
1033                 }
1034                 return _mode;
1035             }
1036             set {
1037                 if (value < DetailsViewMode.ReadOnly || value > DetailsViewMode.Insert) {
1038                     throw new ArgumentOutOfRangeException("value");
1039                 }
1040
1041                 _modeSet = true;
1042                 if (_mode != value) {
1043                     _mode = value;
1044                     if (Initialized) {
1045                         RequiresDataBinding = true;
1046                     }
1047                 }
1048             }
1049         }
1050
1051
1052         [
1053         Browsable(false),
1054         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1055         ]
1056         public virtual int PageCount {
1057             get {
1058                 return _pageCount;
1059             }
1060         }
1061
1062         /// <devdoc>
1063         ///    <para>Gets or sets the index of the currently displayed record.
1064         ///     This property echos the public one so that we can set PageIndex to -1
1065         ///     internally when we switch to insert mode, but users should never do that.</para>
1066         /// </devdoc>
1067         private int PageIndexInternal {
1068             get {
1069                 return _pageIndex;
1070             }
1071             set {
1072                 int currentPageIndex = PageIndexInternal;
1073                 if (value != currentPageIndex) {
1074                     _pageIndex = value;
1075                     if (Initialized) {
1076                         RequiresDataBinding = true;
1077                     }
1078                 }
1079             }
1080         }
1081
1082
1083         /// <devdoc>
1084         /// <para>Gets or sets the index of the currently displayed record.</para>
1085         /// </devdoc>
1086         [
1087         Bindable(true),
1088         DefaultValue(0),
1089         WebCategory("Data"),
1090         WebSysDescription(SR.DetailsView_PageIndex)
1091         ]
1092         public virtual int PageIndex {
1093             get {
1094                 // if we're in design mode, we don't want a change to the mode to set the PageIndex to -1.
1095                 if (Mode == DetailsViewMode.Insert && !DesignMode) {
1096                     return -1;
1097                 }
1098                 return PageIndexInternal;
1099             }
1100             set {
1101                 // since we don't know at property set time how many DataItems we'll have,
1102                 // don't throw if we're above PageCount
1103                 if (value < -1) {
1104                     throw new ArgumentOutOfRangeException("value");
1105                 }
1106                 if (value >= 0) {
1107                     PageIndexInternal = value;
1108                 }
1109             }
1110         }
1111         
1112
1113         /// <devdoc>
1114         /// <para>Gets the settings of the pager buttons for the
1115         /// <see cref='System.Web.UI.WebControls.DetailsView'/>. This
1116         /// property is read-only.</para>
1117         /// </devdoc>
1118         [
1119         WebCategory("Paging"),
1120         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1121         NotifyParentProperty(true),
1122         PersistenceMode(PersistenceMode.InnerProperty),
1123         WebSysDescription(SR.DetailsView_PagerSettings)
1124         ]
1125         public virtual PagerSettings PagerSettings {
1126             get {
1127                 if (_pagerSettings == null) {
1128                     _pagerSettings = new PagerSettings();
1129                     if (IsTrackingViewState) {
1130                         ((IStateManager)_pagerSettings).TrackViewState();
1131                     }
1132                     _pagerSettings.PropertyChanged += new EventHandler(OnPagerPropertyChanged);
1133                 }
1134                 return _pagerSettings;
1135             }
1136         }
1137
1138
1139         /// <devdoc>
1140         /// <para>Gets the style properties of the pager rows for the
1141         /// <see cref='System.Web.UI.WebControls.DetailsView'/>. This
1142         /// property is read-only.</para>
1143         /// </devdoc>
1144         [
1145         WebCategory("Styles"),
1146         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1147         NotifyParentProperty(true),
1148         PersistenceMode(PersistenceMode.InnerProperty),
1149         WebSysDescription(SR.WebControl_PagerStyle)
1150         ]
1151         public TableItemStyle PagerStyle {
1152             get {
1153                 if (_pagerStyle == null) {
1154                     _pagerStyle = new TableItemStyle();
1155                     if (IsTrackingViewState)
1156                         ((IStateManager)_pagerStyle).TrackViewState();
1157                 }
1158                 return _pagerStyle;
1159             }
1160         }
1161
1162
1163         /// <devdoc>
1164         /// <para>Indicates the template to use for a pager item within the DetailsView.
1165         /// </devdoc>
1166         [
1167         Browsable(false),
1168         DefaultValue(null),
1169         PersistenceMode(PersistenceMode.InnerProperty),
1170         TemplateContainer(typeof(DetailsView)),
1171         WebSysDescription(SR.View_PagerTemplate)
1172         ]
1173         public virtual ITemplate PagerTemplate {
1174             get {
1175                 return _pagerTemplate;
1176             }
1177             set {
1178                 _pagerTemplate = value;
1179             }
1180         }
1181
1182
1183         /// <devdoc>
1184         /// <para>Gets a collection of <see cref='System.Web.UI.WebControls.DetailsViewRow'/> objects representing the individual
1185         /// rows within the control.
1186         /// This property is read-only.</para>
1187         /// </devdoc>
1188         [
1189         Browsable(false),
1190         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1191         WebSysDescription(SR.DetailsView_Rows)
1192         ]
1193         public virtual DetailsViewRowCollection Rows {
1194             get {
1195                 if (_rowsCollection == null) {
1196                     if (_rowsArray == null) {
1197                         EnsureChildControls();
1198                     }
1199                     if (_rowsArray == null) {
1200                         _rowsArray = new ArrayList();
1201                     }
1202                     _rowsCollection = new DetailsViewRowCollection(_rowsArray);
1203                 }
1204                 return _rowsCollection;
1205             }
1206         }
1207
1208
1209         [
1210         Browsable(false),
1211         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1212         ]
1213         public IAutoFieldGenerator RowsGenerator {
1214             get {
1215                 return _rowsGenerator;
1216             }
1217             set {
1218                 _rowsGenerator = value;
1219             }
1220         }
1221
1222         private IAutoFieldGenerator RowsGeneratorInternal {
1223             get {
1224                 return RowsGenerator ?? _defaultRowsGenerator;
1225             }
1226         }
1227
1228
1229         /// <devdoc>
1230         /// <para>Indicates the style properties of each row.</para>
1231         /// </devdoc>
1232         [
1233         WebCategory("Styles"),
1234         DefaultValue(null),
1235         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1236         NotifyParentProperty(true),
1237         PersistenceMode(PersistenceMode.InnerProperty),
1238         WebSysDescription(SR.View_RowStyle)
1239         ]
1240         public TableItemStyle RowStyle {
1241             get {
1242                 if (_rowStyle == null) {
1243                     _rowStyle = new TableItemStyle();
1244                     if (IsTrackingViewState)
1245                         ((IStateManager)_rowStyle).TrackViewState();
1246                 }
1247                 return _rowStyle;
1248             }
1249         }
1250
1251
1252         [
1253         Browsable(false),
1254         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1255         ]
1256         public object SelectedValue {
1257             get {
1258                 return DataKey.Value;
1259             }
1260         }
1261
1262         protected override HtmlTextWriterTag TagKey {
1263             get {
1264                 return EnablePagingCallbacks ? 
1265                     HtmlTextWriterTag.Div : HtmlTextWriterTag.Table;
1266             }
1267         }
1268
1269
1270         [
1271         Browsable(false),
1272         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1273         ]
1274         public virtual DetailsViewRow TopPagerRow {
1275             get {
1276                 if (_topPagerRow == null) {
1277                     EnsureChildControls();
1278                 }
1279                 return _topPagerRow;
1280             }
1281         }
1282
1283
1284         /// <devdoc>
1285         /// <para>Occurs when a command is issued from the DetailsView.</para>
1286         /// </devdoc>
1287         [
1288         WebCategory("Action"),
1289         WebSysDescription(SR.DetailsView_OnItemCommand)
1290         ]
1291         public event DetailsViewCommandEventHandler ItemCommand {
1292             add {
1293                 Events.AddHandler(EventItemCommand, value);
1294             }
1295             remove {
1296                 Events.RemoveHandler(EventItemCommand, value);
1297             }
1298         }
1299
1300
1301         /// <devdoc>
1302         /// <para>Occurs when a row is created.</para>
1303         /// </devdoc>
1304         [
1305         WebCategory("Behavior"),
1306         WebSysDescription(SR.DetailsView_OnItemCreated)
1307         ]
1308         public event EventHandler ItemCreated {
1309             add {
1310                 Events.AddHandler(EventItemCreated, value);
1311             }
1312             remove {
1313                 Events.RemoveHandler(EventItemCreated, value);
1314             }
1315         }
1316
1317
1318         /// <devdoc>
1319         /// <para>Occurs when the DetailsView item has been deleted.</para>
1320         /// </devdoc>
1321         [
1322         WebCategory("Action"),
1323         WebSysDescription(SR.DataControls_OnItemDeleted)
1324         ]
1325         public event DetailsViewDeletedEventHandler ItemDeleted {
1326             add {
1327                 Events.AddHandler(EventItemDeleted, value);
1328             }
1329             remove {
1330                 Events.RemoveHandler(EventItemDeleted, value);
1331             }
1332         }
1333
1334
1335         /// <devdoc>
1336         /// <para>Occurs when the DetailsView item is being deleted.</para>
1337         /// </devdoc>
1338         [
1339         WebCategory("Action"),
1340         WebSysDescription(SR.DataControls_OnItemDeleting)
1341         ]
1342         public event DetailsViewDeleteEventHandler ItemDeleting {
1343             add {
1344                 Events.AddHandler(EventItemDeleting, value);
1345             }
1346             remove {
1347                 Events.RemoveHandler(EventItemDeleting, value);
1348             }
1349         }
1350
1351
1352         /// <devdoc>
1353         /// <para>Occurs when the DetailsView item has been inserted.</para>
1354         /// </devdoc>
1355         [
1356         WebCategory("Action"),
1357         WebSysDescription(SR.DataControls_OnItemInserted)
1358         ]
1359         public event DetailsViewInsertedEventHandler ItemInserted {
1360             add {
1361                 Events.AddHandler(EventItemInserted, value);
1362             }
1363             remove {
1364                 Events.RemoveHandler(EventItemInserted, value);
1365             }
1366         }
1367
1368
1369         /// <devdoc>
1370         /// <para>Occurs when the DetailsView item is being inserted.</para>
1371         /// </devdoc>
1372         [
1373         WebCategory("Action"),
1374         WebSysDescription(SR.DataControls_OnItemInserting)
1375         ]
1376         public event DetailsViewInsertEventHandler ItemInserting {
1377             add {
1378                 Events.AddHandler(EventItemInserting, value);
1379             }
1380             remove {
1381                 Events.RemoveHandler(EventItemInserting, value);
1382             }
1383         }
1384
1385
1386         /// <devdoc>
1387         /// <para>Occurs when the DetailsView item has been updated.</para>
1388         /// </devdoc>
1389         [
1390         WebCategory("Action"),
1391         WebSysDescription(SR.DataControls_OnItemUpdated)
1392         ]
1393         public event DetailsViewUpdatedEventHandler ItemUpdated {
1394             add {
1395                 Events.AddHandler(EventItemUpdated, value);
1396             }
1397             remove {
1398                 Events.RemoveHandler(EventItemUpdated, value);
1399             }
1400         }
1401
1402
1403         /// <devdoc>
1404         /// <para>Occurs when the DetailsView item is being updated.</para>
1405         /// </devdoc>
1406         [
1407         WebCategory("Action"),
1408         WebSysDescription(SR.DataControls_OnItemUpdating)
1409         ]
1410         public event DetailsViewUpdateEventHandler ItemUpdating {
1411             add {
1412                 Events.AddHandler(EventItemUpdating, value);
1413             }
1414             remove {
1415                 Events.RemoveHandler(EventItemUpdating, value);
1416             }
1417         }
1418
1419
1420         /// <devdoc>
1421         /// <para>Occurs when the ViewMode has changed.</para>
1422         /// </devdoc>
1423         [
1424         WebCategory("Action"),
1425         WebSysDescription(SR.DetailsView_OnModeChanged)
1426         ]
1427         public event EventHandler ModeChanged {
1428             add {
1429                 Events.AddHandler(EventModeChanged, value);
1430             }
1431             remove {
1432                 Events.RemoveHandler(EventModeChanged, value);
1433             }
1434         }
1435
1436
1437         /// <devdoc>
1438         /// <para>Occurs when the ViewMode is changing.</para>
1439         /// </devdoc>
1440         [
1441         WebCategory("Action"),
1442         WebSysDescription(SR.DetailsView_OnModeChanging)
1443         ]
1444         public event DetailsViewModeEventHandler ModeChanging {
1445             add {
1446                 Events.AddHandler(EventModeChanging, value);
1447             }
1448             remove {
1449                 Events.RemoveHandler(EventModeChanging, value);
1450             }
1451         }
1452
1453
1454         /// <devdoc>
1455         /// <para>Occurs when the DetailsView PageIndex has been changed.</para>
1456         /// </devdoc>
1457         [
1458         WebCategory("Action"),
1459         WebSysDescription(SR.DetailsView_OnPageIndexChanged)
1460         ]
1461         public event EventHandler PageIndexChanged {
1462             add {
1463                 Events.AddHandler(EventPageIndexChanged, value);
1464             }
1465             remove {
1466                 Events.RemoveHandler(EventPageIndexChanged, value);
1467             }
1468         }
1469
1470
1471         /// <devdoc>
1472         /// <para>Occurs when the DetailsView PageIndex is changing.</para>
1473         /// </devdoc>
1474         [
1475         WebCategory("Action"),
1476         WebSysDescription(SR.DetailsView_OnPageIndexChanging)
1477         ]
1478         public event DetailsViewPageEventHandler PageIndexChanging {
1479             add {
1480                 Events.AddHandler(EventPageIndexChanging, value);
1481             }
1482             remove {
1483                 Events.RemoveHandler(EventPageIndexChanging, value);
1484             }
1485         }
1486         
1487         /// <devdoc>
1488         /// <para>Builds the callback argument used in DataControlLinkButtons.</para>
1489         /// </devdoc>
1490         private string BuildCallbackArgument(int pageIndex) {
1491             return "\"" + Convert.ToString(pageIndex, CultureInfo.InvariantCulture) + "|\"";
1492         }
1493
1494
1495         public void ChangeMode(DetailsViewMode newMode) {
1496             Mode = newMode;
1497         }
1498
1499         /// <devdoc>
1500         /// Create a single autogenerated row.  This function can be overridden to create a different AutoGeneratedField.
1501         /// </devdoc>
1502         protected virtual AutoGeneratedField CreateAutoGeneratedRow(AutoGeneratedFieldProperties fieldProperties) {
1503             AutoGeneratedField field = new AutoGeneratedField(fieldProperties.DataField);
1504             string name = fieldProperties.Name;
1505             ((IStateManager)field).TrackViewState();
1506
1507             field.HeaderText = name;
1508             field.SortExpression = name;
1509             field.ReadOnly = fieldProperties.IsReadOnly;
1510             field.DataType = fieldProperties.Type;
1511
1512             return field;
1513         }
1514
1515
1516         /// <summary>
1517         /// Creates the set of AutoGenerated rows.  This function cannot be overridden because then if someone
1518         /// overrides it to add another type of DataControlField to the control, we have to manage the states of those
1519         /// fields along with their types.
1520         /// This could become Obsolete in future versions.
1521         /// </summary>
1522         protected virtual ICollection CreateAutoGeneratedRows(object dataItem) {
1523             return _defaultRowsGenerator.CreateAutoGeneratedFields(dataItem, this);
1524         }
1525
1526
1527         /// <devdoc>
1528         /// <para>Creates the control hierarchy that is used to render the DetailsView.
1529         /// This is called whenever a control hierarchy is needed and the
1530         /// ChildControlsCreated property is false.
1531         /// The implementation assumes that all the children in the controls
1532         /// collection have already been cleared.</para>
1533         /// </devdoc>
1534         protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding) {
1535             PagedDataSource pagedDataSource = null;
1536             int itemIndex = PageIndex;
1537             bool allowPaging = AllowPaging;
1538             int itemCount = 0;
1539             DetailsViewMode mode = Mode;
1540
1541             // if we're in design mode, PageIndex doesn't return -1
1542             if (DesignMode && mode == DetailsViewMode.Insert) {
1543                 itemIndex = -1;
1544             }
1545
1546             if (dataBinding) {
1547                 DataSourceView view = GetData();
1548                 DataSourceSelectArguments arguments = SelectArguments;
1549                 
1550                 if (view == null) {
1551                     throw new HttpException(SR.GetString(SR.DataBoundControl_NullView, ID));
1552                 }
1553
1554                 if (mode != DetailsViewMode.Insert) {
1555                     if (allowPaging && !view.CanPage) {
1556                         if (dataSource != null && !(dataSource is ICollection)) {
1557                             arguments.StartRowIndex = itemIndex;
1558                             arguments.MaximumRows = 1;
1559                             // This should throw an exception saying the data source can't page.
1560                             // We do this because the data source can provide a better error message than we can.
1561                             view.Select(arguments, SelectCallback);
1562                         }
1563                     }
1564
1565                     if (_useServerPaging) {
1566                         if (view.CanRetrieveTotalRowCount) {
1567                             pagedDataSource = CreateServerPagedDataSource(arguments.TotalRowCount);
1568                         }
1569                         else {
1570                             ICollection dataSourceCollection = dataSource as ICollection;
1571                             if (dataSourceCollection == null) {
1572                                 throw new HttpException(SR.GetString(SR.DataBoundControl_NeedICollectionOrTotalRowCount, GetType().Name));
1573                             }
1574                             pagedDataSource = CreateServerPagedDataSource(checked(PageIndex + dataSourceCollection.Count));
1575                         }
1576                     }
1577                     else {
1578                         pagedDataSource = CreatePagedDataSource();
1579                     }
1580                 }
1581             }
1582             else {
1583                 pagedDataSource = CreatePagedDataSource();
1584             }
1585
1586             if (mode != DetailsViewMode.Insert) {
1587                 pagedDataSource.DataSource = dataSource;
1588             }
1589             
1590             IEnumerator dataSourceEnumerator = null;
1591             OrderedDictionary keyTable = KeyTable;
1592
1593             _rowsArray = new ArrayList();
1594             _rowsCollection = null;
1595
1596             if (dataBinding == false) {
1597                 dataSourceEnumerator = dataSource.GetEnumerator();
1598
1599                 ICollection collection = dataSource as ICollection;
1600                 if (collection == null) {
1601                     throw new HttpException(SR.GetString(SR.DataControls_DataSourceMustBeCollectionWhenNotDataBinding));
1602                 }
1603                 itemCount = collection.Count;
1604             } else {
1605                 keyTable.Clear();
1606                 if (dataSource != null) {
1607                     if (mode != DetailsViewMode.Insert) {
1608                         ICollection collection = dataSource as ICollection;
1609                         if ((collection == null) && (pagedDataSource.IsPagingEnabled && !pagedDataSource.IsServerPagingEnabled)) {
1610                             throw new HttpException(SR.GetString(SR.DetailsView_DataSourceMustBeCollection, ID));
1611                         }
1612
1613                         if (pagedDataSource.IsPagingEnabled) {
1614                             itemCount = pagedDataSource.DataSourceCount;
1615                         }
1616                         else if (collection != null) {
1617                             itemCount = collection.Count;
1618                         }
1619                     }
1620                     dataSourceEnumerator = dataSource.GetEnumerator();
1621                 }
1622             }
1623
1624             Table table = CreateTable();
1625             TableRowCollection rows = table.Rows;
1626             bool moveNextSucceeded = false;
1627             object lastItem = null;
1628
1629             Controls.Add(table);
1630
1631             if (dataSourceEnumerator != null) {
1632                 moveNextSucceeded = dataSourceEnumerator.MoveNext();    // goto the first item
1633             }
1634
1635             // if there are no items, only add the tablerow if there's a null template or null text
1636             if (!moveNextSucceeded && mode != DetailsViewMode.Insert) {
1637                 // if we're in insert mode and we're not autogenerating rows, render the rows in insert mode
1638                 if (itemIndex >= 0 || AutoGenerateRows) {
1639                     if (EmptyDataText.Length > 0 || _emptyDataTemplate != null) {
1640                         _rowsArray.Add(CreateRow(0, DataControlRowType.EmptyDataRow, DataControlRowState.Normal, null, rows, null));
1641                     }
1642                     itemCount = 0;
1643                 }
1644             }
1645             else {
1646                 int currentItemIndex = 0;
1647                 if (!_useServerPaging) {
1648                     // skip over the first records that are before the page we're showing
1649                     for (; currentItemIndex < itemIndex; currentItemIndex++) {
1650                         lastItem = dataSourceEnumerator.Current;
1651                         moveNextSucceeded = dataSourceEnumerator.MoveNext();
1652                         if (!moveNextSucceeded) {
1653                             _pageIndex = currentItemIndex;
1654                             pagedDataSource.CurrentPageIndex = currentItemIndex;
1655                             itemIndex = currentItemIndex;                    
1656                             break;  // never throw if the PageIndex is out of range: just fix up the current page and goto the last item.
1657                         }
1658                     }
1659                 }
1660
1661                 if (moveNextSucceeded) {
1662                     _dataItem = dataSourceEnumerator.Current;
1663                 }
1664                 else {
1665                     _dataItem = lastItem;   // if we broke out of the above loop, the current item will be invalid
1666                 }
1667
1668
1669                 // If we're not using server paging and this isn't a collection, or server paging doesn't return a page count, our _pageCount isn't accurate.
1670                 // Loop through the rest of the enumeration to figure out how many items are in it.
1671                 if ((!_useServerPaging && !(dataSource is ICollection)) || (_useServerPaging && itemCount < 0)) {
1672                     itemCount = currentItemIndex;
1673                     while (moveNextSucceeded) {
1674                         itemCount++;
1675                         moveNextSucceeded = dataSourceEnumerator.MoveNext();
1676                     }
1677                 }
1678
1679                 _dataItemIndex = currentItemIndex;
1680
1681                 bool singlePage = itemCount <= 1 && !_useServerPaging; // hide pagers if there's only one item
1682                 if (allowPaging && PagerSettings.Visible && _pagerSettings.IsPagerOnTop && !singlePage && mode != DetailsViewMode.Insert) {
1683                     // top pager
1684                     _topPagerRow = CreateRow(-1, DataControlRowType.Pager, DataControlRowState.Normal, null, rows, pagedDataSource);
1685                 }
1686
1687                 _headerRow = CreateRow(-1, DataControlRowType.Header, DataControlRowState.Normal, null, rows, null);
1688                 if (_headerTemplate == null && HeaderText.Length == 0) {
1689                     _headerRow.Visible = false;
1690                 }
1691
1692                 _rowsArray.AddRange(CreateDataRows(dataBinding, rows, _dataItem));
1693
1694                 if (itemIndex >= 0) {
1695                     string[] keyFields = DataKeyNamesInternal;
1696                     if (dataBinding && (keyFields.Length != 0)) {
1697                         foreach (string keyName in keyFields) {
1698                             object keyValue = DataBinder.GetPropertyValue(_dataItem, keyName);
1699                             keyTable.Add(keyName, keyValue);
1700                         }
1701                         _dataKey = new DataKey(keyTable);
1702                     }
1703                 }
1704
1705                 _footerRow = CreateRow(-1, DataControlRowType.Footer, DataControlRowState.Normal, null, rows, null);
1706                 if (_footerTemplate == null && FooterText.Length == 0) {
1707                     _footerRow.Visible = false;
1708                 }
1709
1710                 if (allowPaging && PagerSettings.Visible && _pagerSettings.IsPagerOnBottom && !singlePage && mode != DetailsViewMode.Insert) {
1711                     // bottom pager
1712                     _bottomPagerRow = CreateRow(-1, DataControlRowType.Pager, DataControlRowState.Normal, null, rows, pagedDataSource);
1713                 }
1714             }
1715
1716             _pageCount = itemCount;
1717
1718             OnItemCreated(EventArgs.Empty);
1719             
1720             if (dataBinding) {
1721                 DataBind(false);
1722             }
1723
1724             return itemCount;
1725         }
1726
1727
1728         /// <devdoc>
1729         /// <para>Creates new control style.</para>
1730         /// </devdoc>
1731         protected override Style CreateControlStyle() {
1732             TableStyle controlStyle = new TableStyle();
1733
1734             // initialize defaults that are different from TableStyle
1735             controlStyle.GridLines = GridLines.Both;
1736             controlStyle.CellSpacing = 0;
1737
1738             return controlStyle;
1739         }
1740
1741         private ICollection CreateDataRows(bool dataBinding, TableRowCollection rows, object dataItem) {
1742             ArrayList rowsArray = new ArrayList();
1743             rowsArray.AddRange(CreateDataRowsFromFields(dataItem, dataBinding, rows));
1744             return rowsArray;
1745         }
1746
1747         private ICollection CreateDataRowsFromFields(object dataItem, bool dataBinding, TableRowCollection rows) {
1748             int fieldCount = 0;
1749             ICollection fields = CreateFieldSet(dataItem, dataBinding);
1750             ArrayList rowsArray = new ArrayList();
1751             if (fields != null)
1752                 fieldCount = fields.Count;
1753
1754             if (fieldCount > 0) {
1755                 DataControlRowType rowType = DataControlRowType.DataRow;
1756                 DataControlRowState masterRowState = DataControlRowState.Normal;
1757                 int dataRowIndex = 0;
1758                 DetailsViewMode mode = Mode;
1759
1760                 if (mode == DetailsViewMode.Edit)
1761                     masterRowState |= DataControlRowState.Edit;
1762                 else if (mode == DetailsViewMode.Insert)
1763                     masterRowState |= DataControlRowState.Insert;
1764
1765                 bool requiresDataBinding = false;
1766                 foreach (DataControlField field in fields) {
1767                     if (field.Initialize(false, this)) {
1768                         requiresDataBinding = true;
1769                     }
1770                     if (DetermineRenderClientScript()) {
1771                         field.ValidateSupportsCallback();
1772                     }
1773
1774                     DataControlRowState rowState = masterRowState;
1775
1776                     if (dataRowIndex % 2 != 0) {
1777                         rowState |= DataControlRowState.Alternate;
1778                     }
1779
1780                     rowsArray.Add(CreateRow(dataRowIndex, rowType, rowState, field, rows, null));
1781
1782                     dataRowIndex++;
1783                 }
1784                 if (requiresDataBinding) {
1785                     RequiresDataBinding = true;
1786                 }
1787             }
1788             return rowsArray;
1789         }
1790
1791         protected override DataSourceSelectArguments CreateDataSourceSelectArguments() {
1792             DataSourceSelectArguments arguments = new DataSourceSelectArguments();
1793             DataSourceView view = GetData();
1794             _useServerPaging = AllowPaging && view.CanPage;
1795
1796             // decide if we should use server-side paging
1797             if (_useServerPaging) {
1798                 arguments.StartRowIndex = PageIndex;
1799                 if (view.CanRetrieveTotalRowCount) {
1800                     arguments.RetrieveTotalRowCount = true;
1801                     arguments.MaximumRows = 1;
1802                 }
1803                 else {
1804                     arguments.MaximumRows = -1;
1805                 }
1806             }
1807
1808             return arguments;
1809         }
1810
1811
1812         /// <devdoc>
1813         /// Creates the set of fields to be used to build up the control
1814         /// hierarchy.
1815         /// When AutoGenerateRows is true, the fields are created to match the
1816         /// datasource and are appended to the set of fields defined in the Fields
1817         /// collection.
1818         /// </devdoc>
1819         protected virtual ICollection CreateFieldSet(object dataItem, bool useDataSource) {
1820             ArrayList fieldsArray = new ArrayList();
1821
1822             if (AutoGenerateRows == true) {
1823                 if (RowsGeneratorInternal is DetailsViewRowsGenerator) {
1824                     ((DetailsViewRowsGenerator)RowsGeneratorInternal).DataItem = dataItem;
1825                     ((DetailsViewRowsGenerator)RowsGeneratorInternal).InDataBinding = useDataSource;
1826                 }
1827                 fieldsArray.AddRange(RowsGeneratorInternal.GenerateFields(this));
1828             }
1829
1830             foreach (DataControlField f in Fields) {
1831                 fieldsArray.Add(f);
1832             }
1833
1834             if (AutoGenerateInsertButton || AutoGenerateDeleteButton || AutoGenerateEditButton) {
1835                 CommandField commandField = new CommandField();
1836                 commandField.ButtonType = ButtonType.Link;
1837
1838                 if (AutoGenerateInsertButton) {
1839                     commandField.ShowInsertButton = true;
1840                 }
1841
1842                 if (AutoGenerateDeleteButton) {
1843                     commandField.ShowDeleteButton = true;
1844                 }
1845
1846                 if (AutoGenerateEditButton) {
1847                     commandField.ShowEditButton = true;
1848                 }
1849                 fieldsArray.Add(commandField);
1850             }
1851
1852             return fieldsArray;
1853         }
1854
1855         /// <devdoc>
1856         /// Creates the pager for NextPrev and NextPrev with First and Last styles
1857         /// </devdoc>
1858         private void CreateNextPrevPager(TableRow row, PagedDataSource pagedDataSource, bool addFirstLastPageButtons) {
1859             PagerSettings pagerSettings = PagerSettings;
1860             string prevPageImageUrl = pagerSettings.PreviousPageImageUrl;
1861             string nextPageImageUrl = pagerSettings.NextPageImageUrl;
1862             bool isFirstPage = pagedDataSource.IsFirstPage;
1863             bool isLastPage = pagedDataSource.IsLastPage;
1864
1865
1866             if (addFirstLastPageButtons && !isFirstPage) {
1867                 string firstPageImageUrl = pagerSettings.FirstPageImageUrl;
1868                 TableCell cell = new TableCell();
1869                 row.Cells.Add(cell);
1870                 IButtonControl firstButton;
1871                 if (firstPageImageUrl.Length > 0) {
1872                     firstButton = new DataControlImageButton(this);
1873                     ((DataControlImageButton)firstButton).ImageUrl = firstPageImageUrl;
1874                     ((DataControlImageButton)firstButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.FirstPageText);
1875                     ((DataControlImageButton)firstButton).EnableCallback(BuildCallbackArgument(0));
1876                 } else {
1877                     firstButton = new DataControlPagerLinkButton(this);
1878                     ((DataControlPagerLinkButton)firstButton).Text = pagerSettings.FirstPageText;
1879                     ((DataControlPagerLinkButton)firstButton).EnableCallback(BuildCallbackArgument(0));
1880                 }
1881                 firstButton.CommandName = DataControlCommands.PageCommandName;
1882                 firstButton.CommandArgument = DataControlCommands.FirstPageCommandArgument;
1883                 cell.Controls.Add((Control)firstButton);
1884             }
1885
1886             if (!isFirstPage) {
1887                 IButtonControl prevButton;
1888                 TableCell cell = new TableCell();
1889                 row.Cells.Add(cell);
1890                 if (prevPageImageUrl.Length > 0) {
1891                     prevButton = new DataControlImageButton(this);
1892                     ((DataControlImageButton)prevButton).ImageUrl = prevPageImageUrl;
1893                     ((DataControlImageButton)prevButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.PreviousPageText);
1894                     ((DataControlImageButton)prevButton).EnableCallback(BuildCallbackArgument(PageIndex - 1));
1895                 } else {
1896                     prevButton = new DataControlPagerLinkButton(this);
1897                     ((DataControlPagerLinkButton)prevButton).Text = pagerSettings.PreviousPageText;
1898                     ((DataControlPagerLinkButton)prevButton).EnableCallback(BuildCallbackArgument(PageIndex - 1));
1899                 }
1900                 prevButton.CommandName = DataControlCommands.PageCommandName;
1901                 prevButton.CommandArgument = DataControlCommands.PreviousPageCommandArgument;
1902                 cell.Controls.Add((Control)prevButton);
1903             }
1904
1905
1906             if (!isLastPage) {
1907                 IButtonControl nextButton;
1908                 TableCell cell = new TableCell();
1909                 row.Cells.Add(cell);
1910                 if (nextPageImageUrl.Length > 0) {
1911                     nextButton = new DataControlImageButton(this);
1912                     ((DataControlImageButton)nextButton).ImageUrl = nextPageImageUrl;
1913                     ((DataControlImageButton)nextButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.NextPageText);
1914                     ((DataControlImageButton)nextButton).EnableCallback(BuildCallbackArgument(PageIndex + 1));
1915                 } else {
1916                     nextButton = new DataControlPagerLinkButton(this);
1917                     ((DataControlPagerLinkButton)nextButton).Text = pagerSettings.NextPageText;
1918                     ((DataControlPagerLinkButton)nextButton).EnableCallback(BuildCallbackArgument(PageIndex + 1));
1919                 }
1920                 nextButton.CommandName = DataControlCommands.PageCommandName;
1921                 nextButton.CommandArgument = DataControlCommands.NextPageCommandArgument;
1922                 cell.Controls.Add((Control)nextButton);
1923             }
1924
1925             if (addFirstLastPageButtons && !isLastPage) {
1926                 string lastPageImageUrl = pagerSettings.LastPageImageUrl;
1927                 IButtonControl lastButton;
1928                 TableCell cell = new TableCell();
1929                 row.Cells.Add(cell);
1930                 if (lastPageImageUrl.Length > 0) {
1931                     lastButton = new DataControlImageButton(this);
1932                     ((DataControlImageButton)lastButton).ImageUrl = lastPageImageUrl;
1933                     ((DataControlImageButton)lastButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.LastPageText);
1934                     ((DataControlImageButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
1935                 } else {
1936                     lastButton = new DataControlPagerLinkButton(this);
1937                     ((DataControlPagerLinkButton)lastButton).Text = pagerSettings.LastPageText;
1938                     ((DataControlPagerLinkButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
1939                 }
1940                 lastButton.CommandName = DataControlCommands.PageCommandName;
1941                 lastButton.CommandArgument = DataControlCommands.LastPageCommandArgument;
1942                 cell.Controls.Add((Control)lastButton);
1943             }
1944         }
1945
1946         /// <devdoc>
1947         /// Creates the pager for NextPrev and NextPrev with First and Last styles
1948         /// </devdoc>
1949         private void CreateNumericPager(TableRow row, PagedDataSource pagedDataSource, bool addFirstLastPageButtons) {
1950             PagerSettings pagerSettings = PagerSettings;
1951
1952             int pages = pagedDataSource.PageCount;
1953             int currentPage = pagedDataSource.CurrentPageIndex + 1;
1954             int pageSetSize = pagerSettings.PageButtonCount;
1955             int pagesShown = pageSetSize;
1956             int firstDisplayedPage = FirstDisplayedPageIndex + 1;   // first page displayed on last postback
1957
1958             // ensure the number of pages we show isn't more than the number of pages that do exist
1959             if (pages < pagesShown)
1960                 pagesShown = pages;
1961
1962             // initialize to the first page set, i.e., pages 1 through number of pages shown
1963             int firstPage = 1;
1964             int lastPage = pagesShown;
1965
1966             if (currentPage > lastPage) {
1967                 // The current page is not in the first page set, then we need to slide the
1968                 // range of pages shown by adjusting firstPage and lastPage
1969                 int currentPageSet = (currentPage - 1) / pageSetSize;
1970                 bool currentPageInLastDisplayRange = currentPage - firstDisplayedPage >= 0 && currentPage - firstDisplayedPage < pageSetSize;
1971                 if (firstDisplayedPage > 0 && currentPageInLastDisplayRange) {
1972                     firstPage = firstDisplayedPage;
1973                 }
1974                 else {
1975                     firstPage = currentPageSet * pageSetSize + 1;
1976                 }
1977                 lastPage = firstPage + pageSetSize - 1;
1978
1979                 // now bring back lastPage into the range if its exceeded the number of pages
1980                 if (lastPage > pages)
1981                     lastPage = pages;
1982
1983                 // if theres room to show more pages from the previous page set, then adjust
1984                 // the first page accordingly
1985                 if (lastPage - firstPage + 1 < pageSetSize) {
1986                     firstPage = Math.Max(1, lastPage - pageSetSize + 1);
1987                 }
1988                 FirstDisplayedPageIndex = firstPage - 1;
1989             }
1990
1991             LinkButton button;
1992
1993             if (addFirstLastPageButtons && currentPage != 1 && firstPage != 1) {
1994                 string firstPageImageUrl = pagerSettings.FirstPageImageUrl;
1995                 IButtonControl firstButton;
1996                 TableCell cell = new TableCell();
1997                 row.Cells.Add(cell);
1998                 
1999                 if (firstPageImageUrl.Length > 0) {
2000                     firstButton = new DataControlImageButton(this);
2001                     ((DataControlImageButton)firstButton).ImageUrl = firstPageImageUrl;
2002                     ((DataControlImageButton)firstButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.FirstPageText);
2003                     ((DataControlImageButton)firstButton).EnableCallback(BuildCallbackArgument(0));
2004                 } else {
2005                     firstButton = new DataControlPagerLinkButton(this);
2006                     ((DataControlPagerLinkButton)firstButton).Text = pagerSettings.FirstPageText;
2007                     ((DataControlPagerLinkButton)firstButton).EnableCallback(BuildCallbackArgument(0));
2008                 }
2009                 firstButton.CommandName = DataControlCommands.PageCommandName;
2010                 firstButton.CommandArgument = DataControlCommands.FirstPageCommandArgument;
2011                 cell.Controls.Add((Control)firstButton);
2012             }
2013
2014             if (firstPage != 1) {
2015                 TableCell cell = new TableCell();
2016                 row.Cells.Add(cell);
2017                 
2018                 button = new DataControlPagerLinkButton(this);
2019                 button.Text = "...";
2020                 button.CommandName = DataControlCommands.PageCommandName;
2021                 button.CommandArgument = (firstPage - 1).ToString(NumberFormatInfo.InvariantInfo);
2022                 ((DataControlPagerLinkButton)button).EnableCallback(BuildCallbackArgument(firstPage - 2));
2023                 cell.Controls.Add(button);
2024             }
2025
2026             for (int i = firstPage; i <= lastPage; i++) {
2027                 TableCell cell = new TableCell();
2028                 row.Cells.Add(cell);
2029                 
2030                 string pageString = (i).ToString(NumberFormatInfo.InvariantInfo);
2031                 if (i == currentPage) {
2032                     Label label = new Label();
2033
2034                     label.Text = pageString;
2035                     cell.Controls.Add(label);
2036                 } else {
2037                     button = new DataControlPagerLinkButton(this);
2038                     
2039                     button.Text = pageString;
2040                     button.CommandName = DataControlCommands.PageCommandName;
2041                     button.CommandArgument = pageString;
2042                     ((DataControlPagerLinkButton)button).EnableCallback(BuildCallbackArgument(i - 1));
2043                     cell.Controls.Add(button);
2044                 }
2045             }
2046
2047             if (pages > lastPage) {
2048                 TableCell cell = new TableCell();
2049                 row.Cells.Add(cell);
2050                 button = new DataControlPagerLinkButton(this);
2051                 
2052                 button.Text = "...";
2053                 button.CommandName = DataControlCommands.PageCommandName;
2054                 button.CommandArgument = (lastPage + 1).ToString(NumberFormatInfo.InvariantInfo);
2055                 ((DataControlPagerLinkButton)button).EnableCallback(BuildCallbackArgument(lastPage));
2056                 cell.Controls.Add(button);
2057             }
2058
2059             bool isLastPageShown = lastPage == pages;
2060             if (addFirstLastPageButtons && currentPage != pages && !isLastPageShown) {
2061                 string lastPageImageUrl = pagerSettings.LastPageImageUrl;
2062                 TableCell cell = new TableCell();
2063                 row.Cells.Add(cell);
2064
2065                 IButtonControl lastButton;
2066                 if (lastPageImageUrl.Length > 0) {
2067                     lastButton = new DataControlImageButton(this);
2068                     ((DataControlImageButton)lastButton).ImageUrl = lastPageImageUrl;
2069                     ((DataControlImageButton)lastButton).AlternateText = HttpUtility.HtmlDecode(pagerSettings.LastPageText);
2070                     ((DataControlImageButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
2071                 } else {
2072                     lastButton = new DataControlPagerLinkButton(this);
2073                     ((DataControlPagerLinkButton)lastButton).Text = pagerSettings.LastPageText;
2074                     ((DataControlPagerLinkButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
2075                 }
2076                 lastButton.CommandName = DataControlCommands.PageCommandName;
2077                 lastButton.CommandArgument = DataControlCommands.LastPageCommandArgument;
2078                 cell.Controls.Add((Control)lastButton);
2079             }
2080         }
2081
2082         private PagedDataSource CreatePagedDataSource() {
2083             PagedDataSource pagedDataSource = new PagedDataSource();
2084
2085             pagedDataSource.CurrentPageIndex = PageIndex;
2086             pagedDataSource.PageSize = 1;
2087             pagedDataSource.AllowPaging = AllowPaging;
2088             pagedDataSource.AllowCustomPaging = false;
2089             pagedDataSource.AllowServerPaging = false;
2090             pagedDataSource.VirtualCount = 0;
2091
2092             return pagedDataSource;
2093         }
2094
2095         private PagedDataSource CreateServerPagedDataSource(int totalRowCount) {
2096             PagedDataSource pagedDataSource = new PagedDataSource();
2097
2098             pagedDataSource.CurrentPageIndex = PageIndex;
2099             pagedDataSource.PageSize = 1;
2100             pagedDataSource.AllowPaging = AllowPaging;
2101             pagedDataSource.AllowCustomPaging = false;
2102             pagedDataSource.AllowServerPaging = true;
2103             pagedDataSource.VirtualCount = totalRowCount;
2104
2105             return pagedDataSource;
2106         }
2107
2108         private DetailsViewRow CreateRow(int rowIndex, DataControlRowType rowType, DataControlRowState rowState, DataControlField field, TableRowCollection rows, PagedDataSource pagedDataSource) {
2109             DetailsViewRow row = CreateRow(rowIndex, rowType, rowState);
2110
2111             rows.Add(row);
2112             if (rowType != DataControlRowType.Pager) {
2113                 InitializeRow(row, field);
2114             } else {
2115                 InitializePager(row, pagedDataSource);
2116             }
2117
2118             return row;
2119         }
2120
2121
2122         /// <devdoc>
2123         /// <para>[To be supplied.]</para>
2124         /// </devdoc>
2125         protected virtual DetailsViewRow CreateRow(int rowIndex, DataControlRowType rowType, DataControlRowState rowState) {
2126             if (rowType == DataControlRowType.Pager) {
2127                 return new DetailsViewPagerRow(rowIndex, rowType, rowState);
2128             }
2129             return new DetailsViewRow(rowIndex, rowType, rowState);
2130         }
2131
2132
2133         /// <devdoc>
2134         /// Creates a new Table, which is the containing table
2135         /// </devdoc>
2136         protected virtual Table CreateTable() {
2137             return new ChildTable(String.IsNullOrEmpty(ID) ? null : ClientID);
2138         }
2139
2140         /// Data bound controls should override PerformDataBinding instead
2141         /// of DataBind.  If DataBind if overridden, the OnDataBinding and OnDataBound events will
2142         /// fire in the wrong order.  However, for backwards compat on ListControl and AdRotator, we 
2143         /// can't seal this method.  It is sealed on all new BaseDataBoundControl-derived controls.
2144         public override sealed void DataBind() {
2145             base.DataBind();
2146         }
2147
2148         public virtual void DeleteItem() {
2149             // use EnableModelVadliation as the causesValdiation param because the hosting page should not
2150             // be validated unless model validation is going to be used
2151             ResetModelValidationGroup(EnableModelValidation, String.Empty);
2152             HandleDelete(String.Empty);
2153         }
2154
2155         private bool DetermineRenderClientScript() {
2156             // In a client script-enabled control, always determine whether to render the
2157             // client script-based functionality.
2158             // The decision should be based on browser capabilities.
2159
2160             if (!_renderClientScriptValid) {
2161                 _renderClientScript = false;
2162     
2163                 if (EnablePagingCallbacks && (Context != null) && (Page != null) && (Page.RequestInternal != null) && Page.Request.Browser.SupportsCallback && !IsParentedToUpdatePanel) {
2164                     HttpBrowserCapabilities browserCaps = Page.Request.Browser;
2165                     bool hasEcmaScript = browserCaps.EcmaScriptVersion.Major > 0;
2166                     bool hasDOM = browserCaps.W3CDomVersion.Major > 0;
2167                     bool isHtml4 = (!StringUtil.EqualsIgnoreCase(browserCaps["tagwriter"], typeof(Html32TextWriter).FullName));
2168                     _renderClientScript = hasEcmaScript && hasDOM && isHtml4;
2169                 }
2170                 _renderClientScriptValid = true;
2171             }
2172             return _renderClientScript;
2173         }
2174
2175         /// <devdoc>
2176         /// Override EnsureDataBound because we don't want to databind when we're in insert mode
2177         /// </devdoc>
2178         protected override void EnsureDataBound() {
2179             // We don't have to databind if we're using a RowsGenerator
2180             if (RequiresDataBinding && Mode == DetailsViewMode.Insert && (!AutoGenerateRows || (AutoGenerateRows && RowsGenerator != null))) {
2181                 OnDataBinding(EventArgs.Empty);
2182
2183                 RequiresDataBinding = false;
2184                 MarkAsDataBound();
2185                 if (AdapterInternal != null) {
2186                     DataBoundControlAdapter dataBoundControlAdapter = AdapterInternal as DataBoundControlAdapter;
2187                     if(dataBoundControlAdapter != null) {
2188                         dataBoundControlAdapter.PerformDataBinding(null);
2189                     }
2190                     else {
2191                         PerformDataBinding(null);
2192                     }
2193                 }
2194                 else {
2195                     PerformDataBinding(null);
2196                 }
2197
2198                 OnDataBound(EventArgs.Empty);
2199             }
2200             else {
2201                 base.EnsureDataBound();
2202             }
2203         }
2204
2205         internal static void ExtractRowValues(object[] fields, DetailsViewRowCollection rows, string[] dataKeyNames, IOrderedDictionary fieldValues, bool includeReadOnlyFields, bool includeKeys) {
2206             int cellIndex;
2207             // Field and row count should match, but if there was no data, or if the user removed some rows,
2208             // these may no longer match.  Make sure we don't exceed the bounds.
2209             for (int i = 0; i < fields.Length && i < rows.Count; i++) {
2210                 // If the row isn't a DataRow then skip it
2211                 if (rows[i].RowType != DataControlRowType.DataRow) {
2212                     continue;
2213                 }
2214                 cellIndex = 0;
2215                 if (((DataControlField)fields[i]).ShowHeader) {
2216                     cellIndex = 1;
2217                 }
2218
2219                 if (!((DataControlField)fields[i]).Visible) {
2220                     continue;
2221                 }
2222
2223                 OrderedDictionary newValues = new OrderedDictionary();
2224
2225                 ((DataControlField)fields[i]).ExtractValuesFromCell(newValues, rows[i].Cells[cellIndex] as DataControlFieldCell, rows[i].RowState, includeReadOnlyFields);
2226                 foreach (DictionaryEntry entry in newValues) {
2227                     if (includeKeys || (Array.IndexOf(dataKeyNames, entry.Key) == -1)) {
2228                         fieldValues[entry.Key] = entry.Value;
2229                     }
2230                 }
2231
2232             }
2233         }
2234
2235         protected virtual void ExtractRowValues(IOrderedDictionary fieldValues, bool includeReadOnlyFields, bool includeKeys) {
2236             if (fieldValues == null) {
2237                 Debug.Assert(false, "DetailsView::ExtractRowValues- must hand in a valid reference to an IDictionary.");
2238                 return;
2239             }
2240
2241             ICollection fieldSet = CreateFieldSet(null, false);
2242             object[] fields = new object[fieldSet.Count];
2243             fieldSet.CopyTo(fields, 0);
2244             DetailsViewRowCollection rows = Rows;
2245             string[] dataKeyNames = DataKeyNamesInternal;
2246
2247             ExtractRowValues(fields, rows, DataKeyNamesInternal, fieldValues, includeReadOnlyFields, includeKeys);
2248         }
2249
2250         protected virtual string GetCallbackResult() {
2251             StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
2252             // 
2253             HtmlTextWriter writer = new HtmlTextWriter(stringWriter);
2254             IStateFormatter2 formatter = Page.CreateStateFormatter();
2255
2256             RenderTableContents(writer);
2257
2258             writer.Flush();
2259             writer.Close();
2260
2261             object dataKeyState = OrderedDictionaryStateHelper.SaveViewState(KeyTable);
2262             string dataKeyString = formatter.Serialize(dataKeyState, Purpose.WebForms_DetailsView_KeyTable);
2263
2264             // this should return the html that goes in the panel, plus the new page info.
2265             return Convert.ToString(PageIndex, CultureInfo.InvariantCulture) + "|" + dataKeyString + "|" + stringWriter.ToString();
2266         }
2267         
2268         protected virtual string GetCallbackScript(IButtonControl buttonControl, string argument) {
2269             if (DetermineRenderClientScript()) {
2270                 if (!String.IsNullOrEmpty(argument)) {
2271                     if (Page != null) {
2272                         Page.ClientScript.RegisterForEventValidation(UniqueID, argument);
2273                     }
2274
2275                     string clientCallbackReference = "javascript:__dv" + ClientID + ".callback";
2276                     return clientCallbackReference + "(" + argument + "); return false;";
2277                 }
2278             }
2279             return null;
2280         }
2281         
2282         private void HandleCancel() {
2283             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2284
2285             DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DefaultMode, true);
2286             OnModeChanging(e);
2287
2288             if (e.Cancel) {
2289                 return;
2290             }
2291
2292             if (isBoundToDataSourceControl) {
2293                 Mode = e.NewMode;
2294                 OnModeChanged(EventArgs.Empty);
2295             }
2296
2297             RequiresDataBinding = true;
2298         }
2299
2300         private void HandleDelete(string commandArg) {
2301             int pageIndex = PageIndex;
2302             if (pageIndex < 0) {    // don't attempt to delete in Insert mode
2303                 return;
2304             }
2305
2306             DataSourceView view = null;
2307             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2308
2309             if (isBoundToDataSourceControl) {
2310                 view = GetData();
2311                 if (view == null) {
2312                     throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2313                 }
2314             }
2315
2316             DetailsViewDeleteEventArgs e = new DetailsViewDeleteEventArgs(pageIndex);
2317
2318
2319             ExtractRowValues(e.Values, true/*includeReadOnlyFields*/, false/*includePrimaryKey*/);
2320             foreach (DictionaryEntry entry in DataKey.Values) {
2321                 e.Keys.Add(entry.Key, entry.Value);
2322                 if (e.Values.Contains(entry.Key)) {
2323                     e.Values.Remove(entry.Key);
2324                 }
2325             }
2326             
2327
2328             OnItemDeleting(e);
2329
2330             if (e.Cancel) {
2331                 return;
2332             }
2333
2334             if (isBoundToDataSourceControl) {
2335                 _deleteKeys = e.Keys;
2336                 _deleteValues = e.Values;
2337                 view.Delete(e.Keys, e.Values, HandleDeleteCallback);
2338             }
2339         }
2340
2341         private bool HandleDeleteCallback(int affectedRows, Exception ex) {
2342             int pageIndex = PageIndex;
2343             DetailsViewDeletedEventArgs dea = new DetailsViewDeletedEventArgs(affectedRows, ex);
2344             dea.SetKeys(_deleteKeys);
2345             dea.SetValues(_deleteValues);
2346
2347             OnItemDeleted(dea);
2348
2349             _deleteKeys = null;
2350             _deleteValues = null;
2351
2352             if (ex != null && !dea.ExceptionHandled) {
2353                 // If there is no validator in the validation group that could make sense
2354                 // of the error, return false to proceed with standard exception handling.
2355                 // But if there is one, we want to let it display its error instead of throwing.
2356                 if (PageIsValidAfterModelException()) {
2357                     return false;
2358                 }
2359             }
2360
2361             if (pageIndex == _pageCount - 1) {
2362                 HandlePage(pageIndex - 1);
2363             }
2364
2365             RequiresDataBinding = true;
2366             return true;
2367         }
2368
2369         private void HandleEdit() {
2370             if (PageIndex < 0) {
2371                 return;
2372             }
2373
2374             DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Edit, false);
2375             OnModeChanging(e);
2376
2377             if (e.Cancel) {
2378                 return;
2379             }
2380
2381             if (IsDataBindingAutomatic) {
2382                 Mode = e.NewMode;
2383                 OnModeChanged(EventArgs.Empty);
2384             }
2385
2386             RequiresDataBinding = true;
2387         }
2388
2389         private bool HandleEvent(EventArgs e, bool causesValidation, string validationGroup) {
2390             bool handled = false;
2391
2392             ResetModelValidationGroup(causesValidation, validationGroup);
2393
2394             DetailsViewCommandEventArgs dce = e as DetailsViewCommandEventArgs;
2395
2396             if (dce != null) {
2397
2398                 OnItemCommand(dce);
2399                 if (dce.Handled) {
2400                     return true;
2401                 }
2402                 handled = true;
2403
2404                 string command = dce.CommandName;
2405                 int newItemIndex = PageIndex;
2406
2407                 if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.PageCommandName)) {
2408                     string itemIndexArg = (string)dce.CommandArgument;
2409
2410                     if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.NextPageCommandArgument)) {
2411                         newItemIndex++;
2412                     } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.PreviousPageCommandArgument)) {
2413                         newItemIndex--;
2414                     } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.FirstPageCommandArgument)) {
2415                         newItemIndex = 0;
2416                     } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.LastPageCommandArgument)) {
2417                         newItemIndex = PageCount - 1;
2418                     } else {
2419                         // argument is page number, and page index is 1 less than that
2420                         newItemIndex = Convert.ToInt32(itemIndexArg, CultureInfo.InvariantCulture) - 1;
2421                     }
2422                     HandlePage(newItemIndex);
2423                 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.EditCommandName)) {
2424                     HandleEdit();
2425                 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.UpdateCommandName)) {
2426                     HandleUpdate((string)dce.CommandArgument, causesValidation);
2427                 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.CancelCommandName)) {
2428                     HandleCancel();
2429                 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.DeleteCommandName)) {
2430                     HandleDelete((string)dce.CommandArgument);
2431                 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.InsertCommandName)) {
2432                     HandleInsert((string)dce.CommandArgument, causesValidation);
2433                 }
2434                 else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.NewCommandName)) {
2435                     HandleNew();
2436                 }
2437                 else {
2438                     handled = HandleCommand(command);
2439                 }
2440             }
2441
2442             return handled;
2443         }
2444
2445         private bool HandleCommand(string commandName) {
2446             DataSourceView view = null;
2447
2448             if (IsDataBindingAutomatic) {
2449                 view = GetData();
2450                 if (view == null) {
2451                     throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2452                 }
2453             }
2454             else {
2455                 return false;
2456             }
2457
2458             if (!view.CanExecute(commandName)) {
2459                 return false;
2460             }
2461             
2462             OrderedDictionary values = new OrderedDictionary();
2463             OrderedDictionary keys = new OrderedDictionary();
2464
2465             ExtractRowValues(values, true /*includeReadOnlyFields*/, false /*includePrimaryKey*/);
2466             foreach (DictionaryEntry entry in DataKey.Values) {
2467                 keys.Add(entry.Key, entry.Value);
2468                 if (values.Contains(entry.Key)) {
2469                     values.Remove(entry.Key);
2470                 }
2471             }
2472
2473             view.ExecuteCommand(commandName, keys, values, HandleCommandCallback);
2474             return true;
2475         }
2476
2477         private bool HandleCommandCallback(int affectedRows, Exception ex) {
2478             if (ex != null) {
2479                 // If there is no validator in the validation group that could make sense
2480                 // of the error, return false to proceed with standard exception handling.
2481                 // But if there is one, we want to let it display its error instead of throwing.
2482                 if (PageIsValidAfterModelException()) {
2483                     return false;
2484                 }
2485             }
2486             
2487             RequiresDataBinding = true;
2488             return true;
2489         }
2490
2491         private void HandleInsert(string commandArg, bool causesValidation) {
2492             if (causesValidation && Page != null && !Page.IsValid) {
2493                 return;
2494             }
2495
2496             if (Mode != DetailsViewMode.Insert) {
2497                 throw new HttpException(SR.GetString(SR.DetailsViewFormView_ControlMustBeInInsertMode, "DetailsView", ID));
2498             }
2499
2500             DataSourceView view = null;
2501             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2502
2503             if (isBoundToDataSourceControl) {
2504                 view = GetData();
2505                 if (view == null) {
2506                     throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2507                 }
2508             }
2509
2510             DetailsViewInsertEventArgs e = new DetailsViewInsertEventArgs(commandArg);
2511
2512
2513             ExtractRowValues(e.Values, false/*includeReadOnlyFields*/, true/*includePrimaryKey*/);
2514             
2515
2516             OnItemInserting(e);
2517
2518             if (e.Cancel) {
2519                 return;
2520             }
2521
2522             if (isBoundToDataSourceControl) {
2523                 _insertValues = e.Values;
2524                 view.Insert(e.Values, HandleInsertCallback);
2525             }
2526         }
2527
2528         private bool HandleInsertCallback(int affectedRows, Exception ex) {
2529             DetailsViewInsertedEventArgs dea = new DetailsViewInsertedEventArgs(affectedRows, ex);
2530             dea.SetValues(_insertValues);
2531             OnItemInserted(dea);
2532
2533             _insertValues = null;
2534             if (ex != null && !dea.ExceptionHandled) {
2535                 // If there is no validator in the validation group that could make sense
2536                 // of the error, return false to proceed with standard exception handling.
2537                 // But if there is one, we want to let it display its error instead of throwing.
2538                 if (PageIsValidAfterModelException()) {
2539                     return false;
2540                 }
2541                 dea.KeepInInsertMode = true;
2542             }
2543
2544             if (IsUsingModelBinders && !Page.ModelState.IsValid) {
2545                 dea.KeepInInsertMode = true;
2546             }
2547
2548             if (!dea.KeepInInsertMode) {
2549                 DetailsViewModeEventArgs eMode = new DetailsViewModeEventArgs(DefaultMode, false);
2550                 OnModeChanging(eMode);
2551                 if (!eMode.Cancel) {
2552                     Mode = eMode.NewMode;
2553                     OnModeChanged(EventArgs.Empty);
2554                     RequiresDataBinding = true;
2555                 }
2556             }
2557             return true;
2558         }
2559
2560         private void HandleNew() {
2561             DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Insert, false);
2562             OnModeChanging(e);
2563
2564             if (e.Cancel) {
2565                 return;
2566             }
2567
2568             if (IsDataBindingAutomatic) {
2569                 Mode = e.NewMode;
2570                 OnModeChanged(EventArgs.Empty);
2571             }
2572
2573             RequiresDataBinding = true;
2574         }
2575
2576         private void HandlePage(int newPage) {
2577             if (!AllowPaging) {
2578                 return;
2579             }
2580
2581             if (PageIndex < 0) {
2582                 return;
2583             }
2584
2585             DetailsViewPageEventArgs e = new DetailsViewPageEventArgs(newPage);
2586             OnPageIndexChanging(e);
2587
2588             if (e.Cancel) {
2589                 return;
2590             }
2591
2592             if (IsDataBindingAutomatic) {
2593                 if (e.NewPageIndex > -1) {
2594                     // if the requested page is out of range and we're already on the last page, don't rebind
2595                     if ((e.NewPageIndex >= PageCount && _pageIndex == PageCount - 1)) {
2596                         return;
2597                     }
2598                     // DevDiv Bugs 188830: Don't clear key table if page is out of range, since control won't be rebound.
2599                     _keyTable = null;
2600                     _pageIndex = e.NewPageIndex;
2601                 }
2602                 else {
2603                     return;
2604                 }
2605             }
2606
2607             OnPageIndexChanged(EventArgs.Empty);
2608             RequiresDataBinding = true;
2609         }
2610
2611         private void HandleUpdate(string commandArg, bool causesValidation) {
2612             if (causesValidation && Page != null && !Page.IsValid) {
2613                 return;
2614             }
2615
2616             if (Mode != DetailsViewMode.Edit) {
2617                 throw new HttpException(SR.GetString(SR.DetailsViewFormView_ControlMustBeInEditMode, "DetailsView", ID));
2618             }
2619
2620             if (PageIndex < 0) {
2621                 return;
2622             }
2623
2624             DataSourceView view = null;
2625             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2626
2627             if (isBoundToDataSourceControl) {
2628                 view = GetData();
2629                 if (view == null) {
2630                     throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2631                 }
2632             }
2633
2634             DetailsViewUpdateEventArgs e = new DetailsViewUpdateEventArgs(commandArg);
2635
2636
2637             foreach (DictionaryEntry entry in BoundFieldValues) {
2638                 e.OldValues.Add(entry.Key, entry.Value);
2639             }
2640
2641             ExtractRowValues(e.NewValues, false/*includeReadOnlyFields*/, true/*includePrimaryKey*/);
2642             foreach (DictionaryEntry entry in DataKey.Values) {
2643                 e.Keys.Add(entry.Key, entry.Value);
2644             }
2645
2646             
2647
2648             OnItemUpdating(e);
2649
2650             if (e.Cancel) {
2651                 return;
2652             }
2653
2654             if (isBoundToDataSourceControl) {
2655                 _updateKeys = e.Keys;
2656                 _updateNewValues = e.NewValues;
2657                 _updateOldValues = e.OldValues;
2658
2659                 view.Update(e.Keys, e.NewValues, e.OldValues, HandleUpdateCallback);
2660             }
2661         }
2662
2663         private bool HandleUpdateCallback(int affectedRows, Exception ex) {
2664             DetailsViewUpdatedEventArgs dea = new DetailsViewUpdatedEventArgs(affectedRows, ex);
2665             dea.SetOldValues(_updateOldValues);
2666             dea.SetNewValues(_updateNewValues);
2667             dea.SetKeys(_updateKeys);
2668
2669             OnItemUpdated(dea);
2670
2671             _updateKeys = null;
2672             _updateOldValues = null;
2673             _updateNewValues = null;
2674
2675             if (ex != null && !dea.ExceptionHandled) {
2676                 // If there is no validator in the validation group that could make sense
2677                 // of the error, return false to proceed with standard exception handling.
2678                 // But if there is one, we want to let it display its error instead of throwing.
2679                 if (PageIsValidAfterModelException()) {
2680                     return false;
2681                 }
2682                 dea.KeepInEditMode = true;
2683             }
2684
2685             if (IsUsingModelBinders && !Page.ModelState.IsValid) {
2686                 dea.KeepInEditMode = true;
2687             }
2688
2689             if (!dea.KeepInEditMode) {
2690                 DetailsViewModeEventArgs eMode = new DetailsViewModeEventArgs(DefaultMode, false);
2691                 OnModeChanging(eMode);
2692                 if (!eMode.Cancel) {
2693                     Mode = eMode.NewMode;
2694                     OnModeChanged(EventArgs.Empty);
2695                     RequiresDataBinding = true;
2696                 }
2697             }
2698             return true;
2699         }
2700
2701
2702         /// <devdoc>
2703         /// <para>
2704         /// Creates a DetailsViewRow that contains the paging UI.
2705         /// The paging UI is a navigation bar that is a built into a single TableCell that
2706         /// spans across all fields of the DetailsView.
2707         /// </para>
2708         /// </devdoc>
2709         protected virtual void InitializePager(DetailsViewRow row, PagedDataSource pagedDataSource) {
2710             TableCell cell = new TableCell();
2711
2712             PagerSettings pagerSettings = PagerSettings;
2713
2714             if (_pagerTemplate != null) {
2715                 _pagerTemplate.InstantiateIn(cell);
2716             }
2717             else {
2718                 PagerTable pagerTable = new PagerTable();
2719                 TableRow pagerTableRow = new TableRow();
2720                 cell.Controls.Add(pagerTable);
2721                 pagerTable.Rows.Add(pagerTableRow);
2722                 switch (pagerSettings.Mode) {
2723                     case PagerButtons.NextPrevious:
2724                         CreateNextPrevPager(pagerTableRow, pagedDataSource, false);
2725                         break;
2726                     case PagerButtons.Numeric:
2727                         CreateNumericPager(pagerTableRow, pagedDataSource, false);
2728                         break;
2729                     case PagerButtons.NextPreviousFirstLast:
2730                         CreateNextPrevPager(pagerTableRow, pagedDataSource, true);
2731                         break;
2732                     case PagerButtons.NumericFirstLast:
2733                         CreateNumericPager(pagerTableRow, pagedDataSource, true);
2734                         break;
2735                 }
2736             }
2737             cell.ColumnSpan = 2;
2738             row.Cells.Add(cell);
2739         }
2740
2741
2742
2743         /// <devdoc>
2744         /// <para>[To be supplied.]</para>
2745         /// </devdoc>
2746         protected virtual void InitializeRow(DetailsViewRow row, DataControlField field) {
2747             TableCellCollection cells = row.Cells;
2748             DataControlFieldCell contentCell = new DataControlFieldCell(field);
2749             ITemplate contentTemplate = null;
2750             int itemIndex = DataItemIndex;
2751             DataControlRowState rowState = row.RowState;
2752
2753             switch (row.RowType) {
2754                 case DataControlRowType.DataRow:
2755                     if (field.ShowHeader) {
2756                         DataControlFieldCell headerTextCell = new DataControlFieldCell(field);
2757                         field.InitializeCell(headerTextCell, DataControlCellType.Header, rowState, itemIndex);
2758                         cells.Add(headerTextCell);
2759                     }
2760                     else {
2761                         contentCell.ColumnSpan = 2;
2762                     }
2763                     field.InitializeCell(contentCell, DataControlCellType.DataCell, rowState, itemIndex);
2764                     break;
2765                 case DataControlRowType.Header:
2766                     contentTemplate = _headerTemplate;
2767                     contentCell.ColumnSpan = 2;
2768                     string headerText = HeaderText;
2769                     if (_headerTemplate == null && headerText.Length > 0) {
2770                         contentCell.Text = headerText;
2771                     }
2772                     break;
2773                 case DataControlRowType.Footer:
2774                     contentTemplate = _footerTemplate;
2775                     contentCell.ColumnSpan = 2;
2776                     string footerText = FooterText;
2777                     if (_footerTemplate == null && footerText.Length > 0) {
2778                         contentCell.Text = footerText;
2779                     }
2780                     break;
2781                 case DataControlRowType.EmptyDataRow:
2782                     contentTemplate = _emptyDataTemplate;
2783                     string emptyDataText = EmptyDataText;
2784                     if (_emptyDataTemplate == null && emptyDataText.Length > 0) {
2785                         contentCell.Text = emptyDataText;
2786                     }
2787                     break;
2788             }
2789
2790             if (contentTemplate != null) {
2791                 contentTemplate.InstantiateIn(contentCell);
2792             }
2793             cells.Add(contentCell);
2794         }
2795
2796         public virtual void InsertItem(bool causesValidation) {
2797             ResetModelValidationGroup(causesValidation, String.Empty);
2798             HandleInsert(String.Empty, causesValidation);
2799         }
2800
2801
2802         /// <summary>
2803         /// Determines if the specified data type can be bound to.
2804         /// Note : Staring from 4.5, This method is no more being used as a criteria for generating rows when AutoGenerateRows=true.
2805         /// This could become obsolete in future versions.
2806         /// </summary>
2807         public virtual bool IsBindableType(Type type) {
2808             return DataBoundControlHelper.IsBindableType(type, enableEnums: RenderingCompatibility >= VersionUtil.Framework45);
2809         }
2810
2811
2812         /// <devdoc>
2813         /// <para>Loads the control state for those properties that should persist across postbacks
2814         ///   even when EnableViewState=false.</para>
2815         /// </devdoc>
2816         protected internal override void LoadControlState(object savedState) {
2817             // Any properties that could have been set in the persistance need to be
2818             // restored to their defaults if they're not in ControlState, or they will
2819             // be restored to their persisted state instead of their empty state.
2820             _pageIndex = 0;
2821             _defaultMode = DetailsViewMode.ReadOnly;
2822             _dataKeyNames = new string[0];
2823             _pageCount = 0;
2824
2825             object[] state = savedState as object[];
2826             
2827             if (state != null) {
2828                 base.LoadControlState(state[0]);
2829                 if (state[1] != null) {
2830                     _pageIndex = (int)state[1];
2831                 }
2832
2833                 if (state[2] != null) {
2834                     _defaultMode = (DetailsViewMode)state[2];
2835                 }
2836
2837                 // if Mode isn't saved, it should be restored to DefaultMode.  That will happen in Mode's getter,
2838                 // since the persistance state hasn't been loaded yet.
2839                 if (state[3] != null) {
2840                     Mode = (DetailsViewMode)state[3];
2841                 }
2842
2843                 if (state[4] != null) {
2844                     _dataKeyNames = (string[])state[4];
2845                 }
2846
2847                 if (state[5] != null) {
2848                     KeyTable.Clear();
2849                     OrderedDictionaryStateHelper.LoadViewState((OrderedDictionary)KeyTable, (ArrayList)state[5]);
2850                 }
2851
2852                 if (state[6] != null) {
2853                     _pageCount = (int)state[6];
2854                 }
2855             }
2856             else {
2857                 base.LoadControlState(null);
2858             }
2859
2860         }
2861
2862         private bool LoadHiddenFieldState(string pageIndex, string dataKey) {
2863             bool propertyChanged = false;
2864             int oldPageIndex = Int32.Parse(pageIndex, CultureInfo.InvariantCulture);
2865
2866             if (PageIndex != oldPageIndex) {
2867                 propertyChanged = true;
2868
2869                 // since we can't go into insert mode in a callback, oldPageIndex should never be -1 and different from PageIndex
2870                 Debug.Assert(oldPageIndex >= 0, "Page indeces are out of sync from callback hidden field state");
2871                 _pageIndex = oldPageIndex;
2872                 
2873                 string oldDataKeyString = dataKey;
2874
2875                 if (!String.IsNullOrEmpty(oldDataKeyString)) {
2876                     IStateFormatter2 formatter = Page.CreateStateFormatter();
2877                     ArrayList oldDataKeyState = formatter.Deserialize(oldDataKeyString, Purpose.WebForms_DetailsView_KeyTable) as ArrayList;
2878                     if (_keyTable != null) {
2879                         _keyTable.Clear();
2880                     }
2881                     OrderedDictionaryStateHelper.LoadViewState(KeyTable, oldDataKeyState);
2882                 }
2883             }
2884             return propertyChanged;
2885         }
2886
2887
2888         /// <devdoc>
2889         /// <para>Loads a saved state of the <see cref='System.Web.UI.WebControls.DetailsView'/>.</para>
2890         /// </devdoc>
2891         protected override void LoadViewState(object savedState) {            
2892             if (savedState != null) {
2893                 object[] myState = (object[])savedState;
2894
2895                 base.LoadViewState(myState[0]);
2896                 if (myState[1] != null)
2897                     ((IStateManager)PagerStyle).LoadViewState(myState[1]);
2898                 if (myState[2] != null)
2899                     ((IStateManager)HeaderStyle).LoadViewState(myState[2]);
2900                 if (myState[3] != null)
2901                     ((IStateManager)FooterStyle).LoadViewState(myState[3]);
2902                 if (myState[4] != null)
2903                     ((IStateManager)RowStyle).LoadViewState(myState[4]);
2904                 if (myState[5] != null)
2905                     ((IStateManager)AlternatingRowStyle).LoadViewState(myState[5]);
2906                 if (myState[6] != null)
2907                     ((IStateManager)CommandRowStyle).LoadViewState(myState[6]);
2908                 if (myState[7] != null)
2909                     ((IStateManager)EditRowStyle).LoadViewState(myState[7]);
2910                 if (myState[8] != null)
2911                     ((IStateManager)InsertRowStyle).LoadViewState(myState[8]);
2912                 if (myState[9] != null)
2913                     ((IStateManager)FieldHeaderStyle).LoadViewState(myState[9]);
2914                 if (myState[10] != null)
2915                     ((IStateManager)Fields).LoadViewState(myState[10]);
2916                 if (myState[11] != null)
2917                     OrderedDictionaryStateHelper.LoadViewState((OrderedDictionary)BoundFieldValues, (ArrayList)myState[11]);
2918                 if (myState[12] != null)
2919                     ((IStateManager)PagerSettings).LoadViewState(myState[12]);
2920                 if (myState[13] != null)
2921                     ((IStateManager)ControlStyle).LoadViewState(myState[13]);
2922                 if (myState[14] != null) {
2923                     Debug.Assert(RowsGeneratorInternal is IStateManager);
2924                     ((IStateManager)RowsGeneratorInternal).LoadViewState(myState[14]);
2925                 }
2926             }
2927             else {
2928                 base.LoadViewState(null);
2929             }
2930         }
2931
2932
2933         /// <devdoc>
2934         /// </devdoc>
2935         protected override bool OnBubbleEvent(object source, EventArgs e) {
2936             bool causesValidation = false;
2937             string validationGroup = String.Empty;
2938             
2939             DetailsViewCommandEventArgs dvcea = e as DetailsViewCommandEventArgs;
2940             if (dvcea != null) {
2941                 IButtonControl button = dvcea.CommandSource as IButtonControl;
2942                 if (button != null) {
2943                     causesValidation = button.CausesValidation;
2944                     validationGroup = button.ValidationGroup;
2945                 }
2946             }
2947             return HandleEvent(e, causesValidation, validationGroup);
2948         }
2949
2950         protected override void OnDataSourceViewChanged(object sender, EventArgs e) {
2951             _keyTable = null;
2952             base.OnDataSourceViewChanged(sender, e);
2953         }
2954
2955         private void OnFieldsChanged(object sender, EventArgs e) {
2956             if (Initialized) {
2957                 RequiresDataBinding = true;
2958             }
2959         }
2960
2961
2962         /// <devdoc>
2963         /// DetailsView initialization.
2964         /// </devdoc>
2965         protected internal override void OnInit(EventArgs e) {
2966             base.OnInit(e);
2967
2968             if (Page != null) {
2969                 if (DataKeyNames.Length > 0 && !AutoGenerateRows) {
2970                     Page.RegisterRequiresViewStateEncryption();
2971                 }
2972                 Page.RegisterRequiresControlState(this);
2973             }
2974
2975             if (!DesignMode && !String.IsNullOrEmpty(ItemType)) {
2976                 DataBoundControlHelper.EnableDynamicData(this, ItemType);
2977             }
2978         }
2979
2980
2981         /// <devdoc>
2982         /// <para>Raises the <see langword='ItemCommand'/> event.</para>
2983         /// </devdoc>
2984         protected virtual void OnItemCommand(DetailsViewCommandEventArgs e) {
2985             DetailsViewCommandEventHandler handler = (DetailsViewCommandEventHandler)Events[EventItemCommand];
2986             if (handler != null) {
2987                 handler(this, e);
2988             }
2989         }
2990
2991
2992         /// <devdoc>
2993         /// <para>Raises the <see langword='ItemCreated'/> event.</para>
2994         /// </devdoc>
2995         protected virtual void OnItemCreated(EventArgs e) {
2996             EventHandler handler = (EventHandler)Events[EventItemCreated];
2997             if (handler != null) {
2998                 handler(this, e);
2999             }
3000         }
3001
3002
3003         /// <devdoc>
3004         /// <para>Raises the <see langword='ItemDeleted '/>event.</para>
3005         /// </devdoc>
3006         protected virtual void OnItemDeleted(DetailsViewDeletedEventArgs e) {
3007             DetailsViewDeletedEventHandler handler = (DetailsViewDeletedEventHandler)Events[EventItemDeleted];
3008             if (handler != null) handler(this, e);
3009         }
3010
3011
3012         /// <devdoc>
3013         /// <para>Raises the <see langword='Delete'/> event.</para>
3014         /// </devdoc>
3015         protected virtual void OnItemDeleting(DetailsViewDeleteEventArgs e) {
3016             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3017
3018             DetailsViewDeleteEventHandler handler = (DetailsViewDeleteEventHandler)Events[EventItemDeleting];
3019             if (handler != null) {
3020                 handler(this, e);
3021             } else {
3022                 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3023                     throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemDeleting"));
3024                 }
3025             }
3026         }
3027
3028
3029         /// <devdoc>
3030         /// <para>Raises the <see langword='ItemInserted '/>event.</para>
3031         /// </devdoc>
3032         protected virtual void OnItemInserted(DetailsViewInsertedEventArgs e) {
3033             DetailsViewInsertedEventHandler handler = (DetailsViewInsertedEventHandler)Events[EventItemInserted];
3034             if (handler != null) handler(this, e);
3035         }
3036
3037
3038         /// <devdoc>
3039         /// <para>Raises the <see langword='Insert'/> event.</para>
3040         /// </devdoc>
3041         protected virtual void OnItemInserting(DetailsViewInsertEventArgs e) {
3042             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3043
3044             DetailsViewInsertEventHandler handler = (DetailsViewInsertEventHandler)Events[EventItemInserting];
3045             if (handler != null) {
3046                 handler(this, e);
3047             } else {
3048                 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3049                     throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemInserting"));
3050                 }
3051             }
3052         }
3053
3054
3055         /// <devdoc>
3056         /// <para>Raises the <see langword='ItemUpdated '/>event.</para>
3057         /// </devdoc>
3058         protected virtual void OnItemUpdated(DetailsViewUpdatedEventArgs e) {
3059             DetailsViewUpdatedEventHandler handler = (DetailsViewUpdatedEventHandler)Events[EventItemUpdated];
3060             if (handler != null) handler(this, e);
3061         }
3062
3063
3064         /// <devdoc>
3065         /// <para>Raises the <see langword='Update'/> event.</para>
3066         /// </devdoc>
3067         protected virtual void OnItemUpdating(DetailsViewUpdateEventArgs e) {
3068             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3069
3070             DetailsViewUpdateEventHandler handler = (DetailsViewUpdateEventHandler)Events[EventItemUpdating];
3071             if (handler != null) {
3072                 handler(this, e);
3073             } else {
3074                 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3075                     throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemUpdating"));
3076                 }
3077             }
3078         }
3079
3080
3081         /// <devdoc>
3082         /// <para>Raises the <see langword='ModeChanged'/>event.</para>
3083         /// </devdoc>
3084         protected virtual void OnModeChanged(EventArgs e) {
3085             EventHandler handler = (EventHandler)Events[EventModeChanged];
3086             if (handler != null) handler(this, e);
3087         }
3088
3089
3090         /// <devdoc>
3091         /// <para>Raises the <see langword='ModeChanging'/> event.</para>
3092         /// </devdoc>
3093         protected virtual void OnModeChanging(DetailsViewModeEventArgs e) {
3094             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3095
3096             DetailsViewModeEventHandler handler = (DetailsViewModeEventHandler)Events[EventModeChanging];
3097             if (handler != null) {
3098                 handler(this, e);
3099             } else {
3100                 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3101                     throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ModeChanging"));
3102                 }
3103             }
3104         }
3105
3106         /// <devdoc>
3107         /// <para>Raises the <see langword='PageIndexChanged'/>event.</para>
3108         /// </devdoc>
3109         protected virtual void OnPageIndexChanged(EventArgs e) {
3110             EventHandler handler = (EventHandler)Events[EventPageIndexChanged];
3111             if (handler != null) handler(this, e);
3112         }
3113
3114
3115         /// <devdoc>
3116         /// <para>Raises the <see langword='ModeChanging'/> event.</para>
3117         /// </devdoc>
3118         protected virtual void OnPageIndexChanging(DetailsViewPageEventArgs e) {
3119             bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3120
3121             DetailsViewPageEventHandler handler = (DetailsViewPageEventHandler)Events[EventPageIndexChanging];
3122             if (handler != null) {
3123                 handler(this, e);
3124             } else {
3125                 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3126                     throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "PageIndexChanging"));
3127                 }
3128             }
3129         }
3130         
3131         protected override void OnPagePreLoad(object sender, EventArgs e) {
3132             // Load hidden field state here to overwrite control state properties.  LoadViewState and LoadControlState
3133             // may not get called if there's no state in them.  We should allow the user to
3134             // set EnablePagingCallbacks in Page_Load, so don't request from DetermineRenderClientScript here.
3135             if (Page != null && !Page.IsCallback && Page.RequestValueCollection != null) {
3136                 string hiddenFieldID = "__dv" + ClientID + "__hidden";
3137                 string hiddenFieldState = Page.RequestValueCollection[hiddenFieldID];
3138                 if (!String.IsNullOrEmpty(hiddenFieldState)) {
3139                     if (ParseHiddenFieldState(hiddenFieldState)) {
3140                         RequiresDataBinding = true;
3141                     }
3142                 }
3143             }
3144             
3145             base.OnPagePreLoad(sender, e);
3146         }
3147
3148         private void OnPagerPropertyChanged(object sender, EventArgs e) {
3149             if (Initialized) {
3150                 RequiresDataBinding = true;
3151             }
3152         }
3153
3154         private const string startupScriptFormat = @"
3155 var {0} = new DetailsView();
3156 {0}.stateField = document.getElementById('{1}');
3157 {0}.panelElement = document.getElementById('{0}__div');
3158 {0}.pageIndex = {3};
3159 {0}.setStateField();
3160 {0}.callback = function(arg) {{
3161     {2};
3162 }};";
3163
3164         /// <devdoc>
3165         /// <para>Sets up the callback scripts if client script is supported on the client</para>
3166         /// </devdoc>
3167         protected internal override void OnPreRender(EventArgs e) {
3168             base.OnPreRender(e);
3169             if (DetermineRenderClientScript() && Page != null) {
3170                 string clientReference = "__dv" + ClientID;
3171                 ClientScriptManager scriptOM = Page.ClientScript;
3172
3173                 scriptOM.RegisterClientScriptResource(typeof(DetailsView), "DetailsView.js");
3174
3175                 // The return value of GetCallbackEventReference looks like this:
3176                 // "__doCallBack(controlname, script fx that returns arg, "DetailsView_OnCallback, context, errorMethod)"
3177                 string doCallBackCall = scriptOM.GetCallbackEventReference(this, clientReference + ".getHiddenFieldContents(arg)", "DetailsView_OnCallback", clientReference);
3178
3179                 // Hidden field used to post content from DetailsView
3180                 // back to the server
3181                 string hiddenFieldID = clientReference + "__hidden";
3182                 scriptOM.RegisterHiddenField(hiddenFieldID, String.Empty);
3183
3184                 string startupScript = String.Format(CultureInfo.InvariantCulture, startupScriptFormat, clientReference, hiddenFieldID, doCallBackCall, PageIndex);
3185                 scriptOM.RegisterStartupScript(typeof(DetailsView), clientReference, startupScript, true);
3186             }
3187         }
3188
3189         private bool PageIsValidAfterModelException() {
3190             if (_modelValidationGroup == null) {
3191                 return true;
3192             }
3193             Page.Validate(_modelValidationGroup);
3194             return Page.IsValid;
3195         }
3196
3197         /// <devdoc>
3198         /// <para>Parses the information in the hidden field for callbacks and sets members to the values
3199         ///    in the hidden field.  Returns whether properties changed from what was retrieved from controlstate.</para>
3200         /// </devdoc>
3201         private bool ParseHiddenFieldState(string state) {
3202             string[] arguments = state.Split(new char[] {'|'});
3203             if (arguments.Length == 2) {
3204                 return LoadHiddenFieldState(arguments[0], arguments[1]);
3205             }
3206             return false;
3207         }
3208
3209
3210         protected internal override void PerformDataBinding(IEnumerable data) {
3211             base.PerformDataBinding(data);
3212             if (IsDataBindingAutomatic && Mode == DetailsViewMode.Edit && IsViewStateEnabled) {
3213                 BoundFieldValues.Clear();
3214                 ExtractRowValues(BoundFieldValues, true/*includeReadOnlyFields*/, false/*includePrimaryKey*/);
3215             }
3216         }
3217
3218         /// <devdoc>
3219         /// </devdoc>
3220         protected internal virtual void PrepareControlHierarchy() {
3221             // The order of rows is autogenerated data rows, declared rows, then autogenerated command rows
3222             if (Controls.Count < 1) {
3223                 return;
3224             }
3225
3226             Debug.Assert(Controls[0] is Table);
3227
3228             Table childTable = (Table)Controls[0];
3229             childTable.CopyBaseAttributes(this);
3230             if (ControlStyleCreated && !ControlStyle.IsEmpty) {
3231                 childTable.ApplyStyle(ControlStyle);
3232             } else {
3233                 // Since we didn't create a ControlStyle yet, the default
3234                 // settings for the default style of the control need to be applied
3235                 // to the child table control directly
3236                 // 
3237
3238                 childTable.GridLines = GridLines.Both;
3239                 childTable.CellSpacing = 0;
3240             }
3241             childTable.Caption = Caption;
3242             childTable.CaptionAlign = CaptionAlign;
3243
3244             // the composite alternating item style, so we need to do just one
3245             // merge style on the actual item
3246             Style altRowStyle = new TableItemStyle();
3247             altRowStyle.CopyFrom(_rowStyle);
3248             if (_alternatingRowStyle != null) {
3249                 altRowStyle = new TableItemStyle();
3250                 altRowStyle.CopyFrom(_alternatingRowStyle);
3251             }
3252
3253             Style compositeStyle;
3254
3255             TableRowCollection rows = childTable.Rows;
3256
3257             foreach (DetailsViewRow row in rows) {
3258                 compositeStyle = new TableItemStyle();
3259                 DataControlRowState rowState = row.RowState;
3260                 DataControlRowType rowType = row.RowType;
3261                 DataControlFieldCell headerFieldCell = row.Cells[0] as DataControlFieldCell;
3262                 DataControlField field = null;
3263
3264                 if (headerFieldCell != null) {
3265                     field = headerFieldCell.ContainingField;
3266                 }
3267
3268                 switch (rowType) {
3269                     case DataControlRowType.Header:
3270                         compositeStyle = _headerStyle;
3271                         break;
3272
3273                     case DataControlRowType.Footer:
3274                         compositeStyle = _footerStyle;
3275                         break;
3276
3277                     case DataControlRowType.DataRow:
3278                         compositeStyle.CopyFrom(_rowStyle);
3279
3280
3281                         if ((rowState & DataControlRowState.Alternate) != 0) {
3282                             compositeStyle.CopyFrom(altRowStyle);
3283                         }
3284                         if (field is ButtonFieldBase) {
3285                             compositeStyle.CopyFrom(_commandRowStyle);
3286                             break;
3287                         }
3288                         if ((rowState & DataControlRowState.Edit) != 0) {
3289                             compositeStyle.CopyFrom(_editRowStyle);
3290                         }
3291                         if ((rowState & DataControlRowState.Insert) != 0) {
3292                             if (_insertRowStyle != null) {
3293                                 compositeStyle.CopyFrom(_insertRowStyle);
3294                             }
3295                             else {
3296                                 compositeStyle.CopyFrom(_editRowStyle);
3297                             }
3298                         }
3299                         break;
3300
3301                     case DataControlRowType.Pager:
3302                         compositeStyle = _pagerStyle;
3303                         break;
3304                     case DataControlRowType.EmptyDataRow:
3305                         compositeStyle = _emptyDataRowStyle;
3306                         break;
3307                 }
3308
3309                 if (compositeStyle != null && row.Visible) {
3310                     row.MergeStyle(compositeStyle);
3311                 }
3312
3313                 if (rowType == DataControlRowType.DataRow && field != null) {
3314                     if (!field.Visible ||
3315                         (Mode == DetailsViewMode.Insert &&  !field.InsertVisible)) {
3316                         row.Visible = false;
3317                     }
3318                     else {
3319                         int contentCellIndex = 0;
3320                         DataControlFieldCell contentFieldCell = null;
3321
3322                         if (headerFieldCell != null && headerFieldCell.ContainingField.ShowHeader) {
3323                             headerFieldCell.MergeStyle(field.HeaderStyleInternal);
3324                             headerFieldCell.MergeStyle(_fieldHeaderStyle);
3325                             contentCellIndex = 1;
3326                         }
3327                         contentFieldCell = row.Cells[contentCellIndex] as DataControlFieldCell;
3328                         if (contentFieldCell != null) {
3329                             contentFieldCell.MergeStyle(field.ItemStyleInternal);
3330                         }
3331
3332                         foreach (Control control in contentFieldCell.Controls) {
3333                             WebControl webControl = control as WebControl;
3334                             Style fieldControlStyle = field.ControlStyleInternal;
3335                             if (webControl != null && fieldControlStyle != null && !fieldControlStyle.IsEmpty) {
3336                                 webControl.ControlStyle.CopyFrom(fieldControlStyle);
3337                             }
3338                         }
3339                     }
3340                 }
3341             }
3342         }
3343
3344         protected virtual void RaiseCallbackEvent(string eventArgument) {
3345             string[] arguments = eventArgument.Split(new char[] {'|'});
3346             Debug.Assert((arguments != null && (arguments.Length == 4)), "An unexpected number of params came through");
3347
3348             ValidateEvent(UniqueID, "\"" + arguments[0] + "|" + arguments[1] + "\"");
3349
3350             LoadHiddenFieldState(arguments[2], arguments[3]);
3351
3352             int pageNumber = Int32.Parse(arguments[0], CultureInfo.InvariantCulture);
3353             _pageIndex = pageNumber;
3354
3355             DataBind();
3356         }
3357
3358         protected virtual void RaisePostBackEvent(string eventArgument) {
3359             ValidateEvent(UniqueID, eventArgument);
3360
3361             int separatorIndex = eventArgument.IndexOf('$');
3362             if (separatorIndex < 0) {
3363                 return;
3364             }
3365
3366             CommandEventArgs cea = new CommandEventArgs(eventArgument.Substring(0, separatorIndex), eventArgument.Substring(separatorIndex + 1));
3367
3368             DetailsViewCommandEventArgs dvcea = new DetailsViewCommandEventArgs(this, cea);
3369             HandleEvent(dvcea, false, String.Empty);
3370                 }
3371
3372
3373         /// <devdoc>
3374         /// <para>Displays the control on the client.</para>
3375         /// </devdoc>
3376         protected internal override void Render(HtmlTextWriter writer) {
3377             // we don't render the outer div at design time because the designer surface 
3378             // needs a top-level layout element
3379             Render(writer, !DesignMode);
3380         }
3381
3382         private void Render(HtmlTextWriter writer, bool renderPanel) {
3383             if (Page != null) {
3384                 Page.VerifyRenderingInServerForm(this);
3385             }
3386             PrepareControlHierarchy();
3387             if (renderPanel) {
3388                 if (DetermineRenderClientScript()) {
3389                     string clientID = ClientID;
3390                     if (clientID == null) {
3391                         throw new HttpException(SR.GetString(SR.DetailsView_MustBeParented));
3392                     }
3393                     else {
3394                         StringBuilder clientPanelNameBuilder = new StringBuilder("__dv", 9 + clientID.Length);
3395                         clientPanelNameBuilder.Append(clientID);
3396                         clientPanelNameBuilder.Append("__div");
3397                         writer.AddAttribute(HtmlTextWriterAttribute.Id, clientPanelNameBuilder.ToString(), true);
3398                     }
3399                 }
3400                 writer.RenderBeginTag(HtmlTextWriterTag.Div);
3401             }
3402             RenderContents(writer);
3403             if (renderPanel) {
3404                 writer.RenderEndTag();
3405             }
3406         }
3407
3408         private void RenderTableContents(HtmlTextWriter writer) {
3409             Render(writer, false);
3410         }
3411
3412         private void ResetModelValidationGroup(bool causesValidation, string validationGroup) {
3413             _modelValidationGroup = null;
3414             if (causesValidation && Page != null) {
3415                 Page.Validate(validationGroup);
3416                 if (EnableModelValidation) {
3417                     _modelValidationGroup = validationGroup;
3418                 }
3419             }
3420         }
3421
3422         /// <devdoc>
3423         /// <para>Saves the control state for those properties that should persist across postbacks
3424         ///   even when EnableViewState=false.</para>
3425         /// </devdoc>
3426         protected internal override object SaveControlState() {
3427             object baseState = base.SaveControlState();
3428             // LoadControlState won't get called if SaveControlState returned null.  We need to restore
3429             // values that are defaults but different from declarative property sets.
3430             if (baseState != null ||
3431                 _pageIndex != 0 || 
3432                 _mode != _defaultMode || 
3433                 _defaultMode != DetailsViewMode.ReadOnly || 
3434                 (_dataKeyNames != null && _dataKeyNames.Length > 0) ||
3435                 (_keyTable != null && _keyTable.Count > 0) ||
3436                 _pageCount != 0) {
3437
3438                 object[] state = new object[7];
3439                 object pageIndexState = null;
3440                 object modeState = null;
3441                 object defaultModeState = null;
3442                 object keyNamesState = null;
3443                 object keyTableState = null;
3444                 object pageCountState = null;
3445
3446                 if (_pageIndex != 0) {
3447                     pageIndexState = _pageIndex;
3448                 }
3449                 if (_defaultMode != DetailsViewMode.ReadOnly) {
3450                     defaultModeState = (int)_defaultMode;
3451                 }
3452                 // Only save the mode if it's different from the DefaultMode.  Otherwise, the Mode
3453                 // getter will restore it to the DefaultMode value.
3454                 if (_mode != _defaultMode && _modeSet) {
3455                     modeState = (int)_mode;
3456                 }
3457
3458                 if (_dataKeyNames != null && _dataKeyNames.Length > 0) {
3459                     keyNamesState = _dataKeyNames;
3460                 }
3461
3462                 if (_keyTable != null) {
3463                     keyTableState = OrderedDictionaryStateHelper.SaveViewState(_keyTable);
3464                 }
3465
3466                 if (_pageCount != 0) {
3467                     pageCountState = _pageCount;
3468                 }
3469
3470                 state[0] = baseState;
3471                 state[1] = pageIndexState;
3472                 state[2] = defaultModeState;
3473                 state[3] = modeState;
3474                 state[4] = keyNamesState;
3475                 state[5] = keyTableState;
3476                 state[6] = pageCountState;
3477
3478                 return state;
3479             }
3480             return true;    // return a dummy that ensures LoadControlState gets called but minimizes persisted size.
3481         }
3482
3483
3484         /// <devdoc>
3485         /// <para>Saves the current state of the <see cref='System.Web.UI.WebControls.DetailsView'/>.</para>
3486         /// </devdoc>
3487         protected override object SaveViewState() {
3488             object baseState = base.SaveViewState();
3489             object pagerStyleState = (_pagerStyle != null) ? ((IStateManager)_pagerStyle).SaveViewState() : null;
3490             object headerStyleState = (_headerStyle != null) ? ((IStateManager)_headerStyle).SaveViewState() : null;
3491             object footerStyleState = (_footerStyle != null) ? ((IStateManager)_footerStyle).SaveViewState() : null;
3492             object rowStyleState = (_rowStyle != null) ? ((IStateManager)_rowStyle).SaveViewState() : null;
3493             object alternatingRowStyleState = (_alternatingRowStyle != null) ? ((IStateManager)_alternatingRowStyle).SaveViewState() : null;
3494             object commandRowStyleState = (_commandRowStyle != null) ? ((IStateManager)_commandRowStyle).SaveViewState() : null;
3495             object editRowStyleState = (_editRowStyle != null) ? ((IStateManager)_editRowStyle).SaveViewState() : null;
3496             object insertRowStyleState = (_insertRowStyle != null) ? ((IStateManager)_insertRowStyle).SaveViewState() : null;
3497             object fieldHeaderStyleState = (_fieldHeaderStyle != null) ? ((IStateManager)_fieldHeaderStyle).SaveViewState() : null;
3498             object fieldsState = (_fieldCollection != null) ? ((IStateManager)_fieldCollection).SaveViewState() : null;
3499             object boundFieldValuesState = (_boundFieldValues != null) ? OrderedDictionaryStateHelper.SaveViewState(_boundFieldValues) : null;
3500             object pagerSettingsState = (_pagerSettings != null) ? ((IStateManager)_pagerSettings).SaveViewState() : null;
3501             object controlState = ControlStyleCreated ? ((IStateManager)ControlStyle).SaveViewState() : null;
3502
3503             object[] myState = new object[15];
3504             myState[0] = baseState;
3505             myState[1] = pagerStyleState;
3506             myState[2] = headerStyleState;
3507             myState[3] = footerStyleState;
3508             myState[4] = rowStyleState;
3509             myState[5] = alternatingRowStyleState;
3510             myState[6] = commandRowStyleState;
3511             myState[7] = editRowStyleState;
3512             myState[8] = insertRowStyleState;
3513             myState[9] = fieldHeaderStyleState;
3514             myState[10] = fieldsState;
3515             myState[11] = boundFieldValuesState;
3516             myState[12] = pagerSettingsState;
3517             myState[13] = controlState;
3518             myState[14] = RowsGeneratorInternal is IStateManager ? ((IStateManager)RowsGeneratorInternal).SaveViewState() : null;
3519
3520             // note that we always have some state, atleast the RowCount
3521             return myState;
3522         }
3523
3524         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", 
3525           Justification = "A property already exists. This method does additional work.")]
3526         public void SetPageIndex(int index) {
3527             HandlePage(index);
3528         }
3529
3530         private void SelectCallback(IEnumerable data) {
3531             // The data source should have thrown.  If we're here, it didn't.  We'll throw for it
3532             // with a generic message.
3533             throw new HttpException(SR.GetString(SR.DataBoundControl_DataSourceDoesntSupportPaging));
3534         }
3535
3536         /// <devdoc>
3537         /// <para>Marks the starting point to begin tracking and saving changes to the
3538         /// control as part of the control viewstate.</para>
3539         /// </devdoc>
3540         protected override void TrackViewState() {
3541             base.TrackViewState();
3542
3543             if (_fieldCollection != null)
3544                 ((IStateManager)_fieldCollection).TrackViewState();
3545             if (_pagerStyle != null)
3546                 ((IStateManager)_pagerStyle).TrackViewState();
3547             if (_headerStyle != null)
3548                 ((IStateManager)_headerStyle).TrackViewState();
3549             if (_footerStyle != null)
3550                 ((IStateManager)_footerStyle).TrackViewState();
3551             if (_rowStyle != null)
3552                 ((IStateManager)_rowStyle).TrackViewState();
3553             if (_alternatingRowStyle != null)
3554                 ((IStateManager)_alternatingRowStyle).TrackViewState();
3555             if (_commandRowStyle != null)
3556                 ((IStateManager)_commandRowStyle).TrackViewState();
3557             if (_editRowStyle != null)
3558                 ((IStateManager)_editRowStyle).TrackViewState();
3559             if (_insertRowStyle != null)
3560                 ((IStateManager)_insertRowStyle).TrackViewState();
3561             if (_pagerSettings != null)
3562                 ((IStateManager)_pagerSettings).TrackViewState();
3563             if (ControlStyleCreated)
3564                 ((IStateManager)ControlStyle).TrackViewState();
3565         }
3566
3567         public virtual void UpdateItem(bool causesValidation) {
3568             ResetModelValidationGroup(causesValidation, String.Empty);
3569             HandleUpdate(String.Empty, causesValidation);
3570         }
3571
3572         internal override void UpdateModelDataSourceProperties(ModelDataSource modelDataSource) {
3573             Debug.Assert(modelDataSource != null, "A non-null ModelDataSource should be passed in");
3574             string dataKeyName = DataKeyNamesInternal.Length > 0 ? DataKeyNamesInternal[0] : "";
3575             modelDataSource.UpdateProperties(ItemType, SelectMethod, UpdateMethod, InsertMethod, DeleteMethod, dataKeyName);
3576         }
3577
3578         #region IPostBackEventHandler implementation
3579         void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
3580             RaisePostBackEvent(eventArgument);
3581         }
3582         #endregion
3583
3584         #region IPostBackContainer implementation
3585         PostBackOptions IPostBackContainer.GetPostBackOptions(IButtonControl buttonControl) {
3586             if (buttonControl == null) {
3587                 throw new ArgumentNullException("buttonControl");
3588             }
3589
3590             if (buttonControl.CausesValidation) {
3591                 throw new InvalidOperationException(SR.GetString(SR.CannotUseParentPostBackWhenValidating, this.GetType().Name, ID));
3592             }
3593
3594             PostBackOptions options = new PostBackOptions(this, (buttonControl.CommandName + "$" + buttonControl.CommandArgument));
3595             options.RequiresJavaScriptProtocol = true;
3596
3597             return options;
3598         }
3599         #endregion
3600
3601         #region ICallbackContainer implementation
3602         string ICallbackContainer.GetCallbackScript(IButtonControl buttonControl, string argument) {
3603             return GetCallbackScript(buttonControl, argument);
3604         }
3605         #endregion
3606
3607         #region ICallbackEventHandler implementation
3608         void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument) {
3609             RaiseCallbackEvent(eventArgument);
3610         }
3611
3612         // The return value of this function is the argument to the callback handler in
3613         // GetCallbackEventReference.
3614         string ICallbackEventHandler.GetCallbackResult() {
3615             return GetCallbackResult();
3616         }
3617         #endregion
3618         
3619         #region IDataItemContainer implementation
3620         int IDataItemContainer.DataItemIndex {
3621             get {
3622                 return DataItemIndex;
3623             }
3624         }
3625
3626         int IDataItemContainer.DisplayIndex {
3627             get {
3628                 return 0;
3629             }
3630         }
3631         #endregion
3632
3633         #region IDataBoundItemControl implementation
3634
3635         DataKey IDataBoundItemControl.DataKey {
3636             get { 
3637                 return DataKey;
3638             }
3639         }
3640
3641         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
3642                 Justification = "The property is only used to genericly access the databound control's mode, and should only be accessed through the interface")]
3643         DataBoundControlMode IDataBoundItemControl.Mode {
3644             get {
3645                 switch (Mode) {
3646                     case DetailsViewMode.Edit:
3647                         return DataBoundControlMode.Edit;
3648                     case DetailsViewMode.Insert:
3649                         return DataBoundControlMode.Insert;
3650                     case DetailsViewMode.ReadOnly:
3651                         return DataBoundControlMode.ReadOnly;
3652                     default:
3653                         Debug.Fail("Shouldn't get here!");
3654                         return DataBoundControlMode.ReadOnly;
3655                 }
3656             }
3657         }
3658
3659         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3660         string IDataBoundControl.DataSourceID {
3661             get {
3662                 return DataSourceID;
3663             }
3664             set {
3665                 DataSourceID = value;
3666             }
3667         }
3668
3669         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3670         IDataSource IDataBoundControl.DataSourceObject {
3671             get { 
3672                 return DataSourceObject; 
3673             }
3674         }
3675
3676         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3677         object IDataBoundControl.DataSource {
3678             get {
3679                 return DataSource;
3680             }
3681             set {
3682                 DataSource = value;
3683             }
3684         }
3685
3686         string[] IDataBoundControl.DataKeyNames {
3687             get {
3688                 return DataKeyNames;
3689             }
3690             set {
3691                 DataKeyNames = value;
3692             }
3693         }        
3694
3695         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3696         string IDataBoundControl.DataMember {
3697             get {
3698                 return DataMember;
3699             }
3700             set {
3701                 DataMember = value;
3702             }
3703         }
3704
3705         #endregion
3706
3707         #region IFieldControl implementation
3708
3709         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
3710             Justification = "The underlying implementation is not meant to be overridden.")]
3711         IAutoFieldGenerator IFieldControl.FieldsGenerator {
3712             get {
3713                 return RowsGenerator;
3714             }
3715             set {
3716                 RowsGenerator = value;
3717             }
3718         }
3719
3720         #endregion
3721     }
3722 }