1 //------------------------------------------------------------------------------
2 // <copyright file="DetailsView.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.UI.WebControls {
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;
17 using System.Reflection;
18 using System.Security.Permissions;
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;
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.
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
40 [DataKeyProperty("DataKey")]
41 public class DetailsView : CompositeDataBoundControl, IDataItemContainer, ICallbackContainer, ICallbackEventHandler, IPostBackEventHandler, IPostBackContainer, IDataBoundItemControl, IFieldControl {
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();
56 private ITemplate _headerTemplate;
57 private ITemplate _footerTemplate;
58 private ITemplate _pagerTemplate;
59 private ITemplate _emptyDataTemplate;
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;
71 private DetailsViewRow _bottomPagerRow;
72 private DetailsViewRow _footerRow;
73 private DetailsViewRow _headerRow;
74 private DetailsViewRow _topPagerRow;
76 private TableItemStyle _pagerStyle;
77 private PagerSettings _pagerSettings;
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;
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;
97 private bool _renderClientScript;
98 private bool _renderClientScriptValid = false;
100 private IAutoFieldGenerator _rowsGenerator;
101 private DetailsViewRowsGenerator _defaultRowsGenerator = new DetailsViewRowsGenerator();
103 private IOrderedDictionary _deleteKeys;
104 private IOrderedDictionary _deleteValues;
105 private IOrderedDictionary _insertValues;
106 private IOrderedDictionary _updateKeys;
107 private IOrderedDictionary _updateOldValues;
108 private IOrderedDictionary _updateNewValues;
111 /// The name of the method on the page which is called when this Control does an update operation.
117 WebSysDescription(SR.DataBoundControl_UpdateMethod)
119 public new virtual string UpdateMethod {
121 return base.UpdateMethod;
124 base.UpdateMethod = value;
129 /// The name of the method on the page which is called when this Control does a delete operation.
135 WebSysDescription(SR.DataBoundControl_DeleteMethod)
137 public new virtual string DeleteMethod {
139 return base.DeleteMethod;
142 base.DeleteMethod = value;
147 /// The name of the method on the page which is called when this Control does an insert operation.
153 WebSysDescription(SR.DataBoundControl_InsertMethod)
155 public new virtual string InsertMethod {
157 return base.InsertMethod;
160 base.InsertMethod = value;
165 /// <para>Gets or sets a value that indicates whether paging is allowed.</para>
168 WebCategory("Paging"),
170 WebSysDescription(SR.DetailsView_AllowPaging)
172 public virtual bool AllowPaging {
174 object o = ViewState["AllowPaging"];
180 bool oldValue = AllowPaging;
181 if (value != oldValue) {
182 ViewState["AllowPaging"] = value;
184 RequiresDataBinding = true;
192 /// <para>Indicates the style properties of alternating rows.</para>
195 WebCategory("Styles"),
197 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
198 NotifyParentProperty(true),
199 PersistenceMode(PersistenceMode.InnerProperty),
200 WebSysDescription(SR.DetailsView_AlternatingRowStyle)
202 public TableItemStyle AlternatingRowStyle {
204 if (_alternatingRowStyle == null) {
205 _alternatingRowStyle = new TableItemStyle();
206 if (IsTrackingViewState)
207 ((IStateManager)_alternatingRowStyle).TrackViewState();
209 return _alternatingRowStyle;
215 /// <para>Gets or sets a value that indicates whether a button field for deleting will automatically
216 /// be created.</para>
219 WebCategory("Behavior"),
221 WebSysDescription(SR.DetailsView_AutoGenerateDeleteButton)
223 public virtual bool AutoGenerateDeleteButton {
225 object o = ViewState["AutoGenerateDeleteButton"];
231 bool oldValue = AutoGenerateDeleteButton;
232 if (value != oldValue) {
233 ViewState["AutoGenerateDeleteButton"] = value;
235 RequiresDataBinding = true;
243 /// <para>Gets or sets a value that indicates whether an edit field will automatically
244 /// be created.</para>
247 WebCategory("Behavior"),
249 WebSysDescription(SR.DetailsView_AutoGenerateEditButton)
251 public virtual bool AutoGenerateEditButton {
253 object o = ViewState["AutoGenerateEditButton"];
259 bool oldValue = AutoGenerateEditButton;
260 if (value != oldValue) {
261 ViewState["AutoGenerateEditButton"] = value;
263 RequiresDataBinding = true;
271 /// <para>Gets or sets a value that indicates whether an insert field will automatically
272 /// be created.</para>
275 WebCategory("Behavior"),
277 WebSysDescription(SR.DetailsView_AutoGenerateInsertButton)
279 public virtual bool AutoGenerateInsertButton {
281 object o = ViewState["AutoGenerateInsertButton"];
287 bool oldValue = AutoGenerateInsertButton;
288 if (value != oldValue) {
289 ViewState["AutoGenerateInsertButton"] = value;
291 RequiresDataBinding = true;
299 /// <para>Gets or sets a value that indicates whether fields will automatically
300 /// be created for each bound data field.</para>
303 WebCategory("Behavior"),
305 WebSysDescription(SR.DetailsView_AutoGenerateRows)
307 public virtual bool AutoGenerateRows {
309 object o = ViewState["AutoGenerateRows"];
315 bool oldValue = AutoGenerateRows;
316 if (value != oldValue) {
317 ViewState["AutoGenerateRows"] = value;
319 RequiresDataBinding = true;
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>
331 WebCategory("Appearance"),
333 Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
335 WebSysDescription(SR.WebControl_BackImageUrl)
337 public virtual string BackImageUrl {
339 if (ControlStyleCreated == false) {
342 return((TableStyle)ControlStyle).BackImageUrl;
345 ((TableStyle)ControlStyle).BackImageUrl = value;
352 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
354 public virtual DetailsViewRow BottomPagerRow {
356 if (_bottomPagerRow == null) {
357 EnsureChildControls();
359 return _bottomPagerRow;
363 private IOrderedDictionary BoundFieldValues {
365 if (_boundFieldValues == null) {
366 int capacity = Fields.Count;
367 if (AutoGenerateRows) {
370 _boundFieldValues = new OrderedDictionary(capacity);
372 return _boundFieldValues;
380 WebCategory("Accessibility"),
381 WebSysDescription(SR.DataControls_Caption)
383 public virtual string Caption {
385 string s = (string)ViewState["Caption"];
386 return (s != null) ? s : String.Empty;
389 ViewState["Caption"] = value;
395 DefaultValue(TableCaptionAlign.NotSet),
396 WebCategory("Accessibility"),
397 WebSysDescription(SR.WebControl_CaptionAlign)
399 public virtual TableCaptionAlign CaptionAlign {
401 object o = ViewState["CaptionAlign"];
402 return (o != null) ? (TableCaptionAlign)o : TableCaptionAlign.NotSet;
405 if ((value < TableCaptionAlign.NotSet) ||
406 (value > TableCaptionAlign.Right)) {
407 throw new ArgumentOutOfRangeException("value");
409 ViewState["CaptionAlign"] = value;
416 /// <para>Indicates the amount of space between cells.</para>
419 WebCategory("Layout"),
421 WebSysDescription(SR.DetailsView_CellPadding)
423 public virtual int CellPadding {
425 if (ControlStyleCreated == false) {
428 return((TableStyle)ControlStyle).CellPadding;
431 ((TableStyle)ControlStyle).CellPadding = value;
437 /// <para>Gets or sets the amount of space between the contents of
438 /// a cell and the cell's border.</para>
441 WebCategory("Layout"),
443 WebSysDescription(SR.DetailsView_CellSpacing)
445 public virtual int CellSpacing {
447 if (ControlStyleCreated == false) {
450 return((TableStyle)ControlStyle).CellSpacing;
453 ((TableStyle)ControlStyle).CellSpacing = value;
459 /// <para>Indicates the style properties of command rows.</para>
462 WebCategory("Styles"),
464 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
465 NotifyParentProperty(true),
466 PersistenceMode(PersistenceMode.InnerProperty),
467 WebSysDescription(SR.DetailsView_CommandRowStyle)
469 public TableItemStyle CommandRowStyle {
471 if (_commandRowStyle == null) {
472 _commandRowStyle = new TableItemStyle();
473 if (IsTrackingViewState)
474 ((IStateManager)_commandRowStyle).TrackViewState();
476 return _commandRowStyle;
483 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
485 public DetailsViewMode CurrentMode {
491 // implement this publicly so DataBinder.Eval(container.DataItem, "x") still works.
494 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
496 public virtual object DataItem {
498 if (CurrentMode == DetailsViewMode.Insert) {
507 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
509 public int DataItemCount {
517 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
519 public virtual int DataItemIndex {
521 if (CurrentMode == DetailsViewMode.Insert) {
524 return _dataItemIndex;
531 Editor("System.Web.UI.Design.WebControls.DataFieldEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
532 TypeConverterAttribute(typeof(StringArrayConverter)),
534 WebSysDescription(SR.DataControls_DataKeyNames)
536 public virtual string[] DataKeyNames {
538 object o = _dataKeyNames;
540 return(string[])((string[])o).Clone();
542 return new string[0];
545 if (!DataBoundControlHelper.CompareStringArrays(value, DataKeyNamesInternal)) {
547 _dataKeyNames = (string[])value.Clone();
550 _dataKeyNames = null;
555 RequiresDataBinding = true;
561 // This version doesn't clone the array
562 private string[] DataKeyNamesInternal {
564 object o = _dataKeyNames;
568 return new string[0];
576 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
577 WebSysDescription(SR.DetailsView_DataKey)
579 public virtual DataKey DataKey {
581 if (_dataKey == null) {
582 _dataKey = new DataKey(KeyTable);
590 WebCategory("Behavior"),
591 DefaultValue(DetailsViewMode.ReadOnly),
592 WebSysDescription(SR.View_DefaultMode)
594 public virtual DetailsViewMode DefaultMode {
599 if (value < DetailsViewMode.ReadOnly || value > DetailsViewMode.Insert) {
600 throw new ArgumentOutOfRangeException("value");
602 _defaultMode = value;
608 /// <para>Indicates the style properties of each row when in edit mode.</para>
611 WebCategory("Styles"),
613 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
614 NotifyParentProperty(true),
615 PersistenceMode(PersistenceMode.InnerProperty),
616 WebSysDescription(SR.View_EditRowStyle)
618 public TableItemStyle EditRowStyle {
620 if (_editRowStyle == null) {
621 _editRowStyle = new TableItemStyle();
622 if (IsTrackingViewState)
623 ((IStateManager)_editRowStyle).TrackViewState();
625 return _editRowStyle;
631 /// <para>Indicates the style properties of null rows.</para>
634 WebCategory("Styles"),
636 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
637 NotifyParentProperty(true),
638 PersistenceMode(PersistenceMode.InnerProperty),
639 WebSysDescription(SR.View_EmptyDataRowStyle)
641 public TableItemStyle EmptyDataRowStyle {
643 if (_emptyDataRowStyle == null) {
644 _emptyDataRowStyle = new TableItemStyle();
645 if (IsTrackingViewState)
646 ((IStateManager)_emptyDataRowStyle).TrackViewState();
648 return _emptyDataRowStyle;
654 /// <para>Indicates the template to use when no records are returned from the datasource within the DetailsView.
659 PersistenceMode(PersistenceMode.InnerProperty),
660 TemplateContainer(typeof(DetailsView)),
661 WebSysDescription(SR.View_EmptyDataTemplate)
663 public virtual ITemplate EmptyDataTemplate {
665 return _emptyDataTemplate;
668 _emptyDataTemplate = value;
674 /// <para>The header text displayed if no EmptyDataTemplate is defined.
678 WebCategory("Appearance"),
680 WebSysDescription(SR.View_EmptyDataText),
682 public virtual String EmptyDataText {
684 object o = ViewState["EmptyDataText"];
691 ViewState["EmptyDataText"] = value;
696 WebCategory("Behavior"),
698 WebSysDescription(SR.DataBoundControl_EnableModelValidation)
700 public virtual bool EnableModelValidation {
702 object o = ViewState["EnableModelValidation"];
709 ViewState["EnableModelValidation"] = value;
714 WebCategory("Behavior"),
716 WebSysDescription(SR.DetailsView_EnablePagingCallbacks)
718 public virtual bool EnablePagingCallbacks {
720 object o = ViewState["EnablePagingCallbacks"];
727 ViewState["EnablePagingCallbacks"] = value;
733 /// <para>Indicates the style properties of the header column.</para>
736 WebCategory("Styles"),
738 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
739 NotifyParentProperty(true),
740 PersistenceMode(PersistenceMode.InnerProperty),
741 WebSysDescription(SR.DetailsView_FieldHeaderStyle)
743 public TableItemStyle FieldHeaderStyle {
745 if (_fieldHeaderStyle == null) {
746 _fieldHeaderStyle = new TableItemStyle();
747 if (IsTrackingViewState)
748 ((IStateManager)_fieldHeaderStyle).TrackViewState();
750 return _fieldHeaderStyle;
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>
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)
766 public virtual DataControlFieldCollection Fields {
768 if (_fieldCollection == null) {
769 _fieldCollection = new DataControlFieldCollection();
770 _fieldCollection.FieldsChanged += new EventHandler(OnFieldsChanged);
771 if (IsTrackingViewState)
772 ((IStateManager)_fieldCollection).TrackViewState();
774 return _fieldCollection;
778 private int FirstDisplayedPageIndex {
780 object o = ViewState["FirstDisplayedPageIndex"];
787 ViewState["FirstDisplayedPageIndex"] = value;
794 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
796 public virtual DetailsViewRow FooterRow {
798 if (_footerRow == null) {
799 EnsureChildControls();
807 /// <para>Indicates the style properties of the footer row.</para>
810 WebCategory("Styles"),
812 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
813 NotifyParentProperty(true),
814 PersistenceMode(PersistenceMode.InnerProperty),
815 WebSysDescription(SR.DetailsView_FooterStyle)
817 public TableItemStyle FooterStyle {
819 if (_footerStyle == null) {
820 _footerStyle = new TableItemStyle();
821 if (IsTrackingViewState)
822 ((IStateManager)_footerStyle).TrackViewState();
830 /// <para>Indicates the template to use for a footer item within the DetailsView.
835 PersistenceMode(PersistenceMode.InnerProperty),
836 TemplateContainer(typeof(DetailsView)),
837 WebSysDescription(SR.DetailsView_FooterTemplate)
839 public virtual ITemplate FooterTemplate {
841 return _footerTemplate;
844 _footerTemplate = value;
850 /// <para>The header text displayed if no FooterTemplate is defined.
854 WebCategory("Appearance"),
856 WebSysDescription(SR.View_FooterText),
858 public virtual String FooterText {
860 object o = ViewState["FooterText"];
867 ViewState["FooterText"] = value;
873 /// <para>Gets or sets a value that specifies the grid line style.</para>
876 WebCategory("Appearance"),
877 DefaultValue(GridLines.Both),
878 WebSysDescription(SR.DataControls_GridLines)
880 public virtual GridLines GridLines {
882 if (ControlStyleCreated == false) {
883 return GridLines.Both;
885 return((TableStyle)ControlStyle).GridLines;
888 ((TableStyle)ControlStyle).GridLines = value;
895 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
897 public virtual DetailsViewRow HeaderRow {
899 if (_headerRow == null) {
900 EnsureChildControls();
908 /// <para>Indicates the style properties of the header row.</para>
911 WebCategory("Styles"),
913 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
914 NotifyParentProperty(true),
915 PersistenceMode(PersistenceMode.InnerProperty),
916 WebSysDescription(SR.WebControl_HeaderStyle)
918 public TableItemStyle HeaderStyle {
920 if (_headerStyle == null) {
921 _headerStyle = new TableItemStyle();
922 if (IsTrackingViewState)
923 ((IStateManager)_headerStyle).TrackViewState();
931 /// <para>Indicates the template to use for a header item within the DetailsView.
936 PersistenceMode(PersistenceMode.InnerProperty),
937 TemplateContainer(typeof(DetailsView)),
938 WebSysDescription(SR.WebControl_HeaderTemplate)
940 public virtual ITemplate HeaderTemplate {
942 return _headerTemplate;
945 _headerTemplate = value;
951 /// <para>The header text displayed if no HeaderTemplate is defined.
955 WebCategory("Appearance"),
957 WebSysDescription(SR.View_HeaderText),
959 public virtual String HeaderText {
961 object o = ViewState["HeaderText"];
968 ViewState["HeaderText"] = value;
974 /// <para>Gets or sets a value that specifies the alignment of a rows with respect
975 /// surrounding text.</para>
979 DefaultValue(HorizontalAlign.NotSet),
980 WebSysDescription(SR.WebControl_HorizontalAlign)
982 public virtual HorizontalAlign HorizontalAlign {
984 if (ControlStyleCreated == false) {
985 return HorizontalAlign.NotSet;
987 return((TableStyle)ControlStyle).HorizontalAlign;
990 ((TableStyle)ControlStyle).HorizontalAlign = value;
996 /// <para>Indicates the style properties of each row when in insert mode.</para>
999 WebCategory("Styles"),
1001 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1002 NotifyParentProperty(true),
1003 PersistenceMode(PersistenceMode.InnerProperty),
1004 WebSysDescription(SR.View_InsertRowStyle)
1006 public TableItemStyle InsertRowStyle {
1008 if (_insertRowStyle == null) {
1009 _insertRowStyle = new TableItemStyle();
1010 if (IsTrackingViewState)
1011 ((IStateManager)_insertRowStyle).TrackViewState();
1013 return _insertRowStyle;
1017 private OrderedDictionary KeyTable {
1019 if (_keyTable == null) {
1020 _keyTable = new OrderedDictionary(DataKeyNamesInternal.Length);
1027 private DetailsViewMode Mode {
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;
1037 if (value < DetailsViewMode.ReadOnly || value > DetailsViewMode.Insert) {
1038 throw new ArgumentOutOfRangeException("value");
1042 if (_mode != value) {
1045 RequiresDataBinding = true;
1054 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1056 public virtual int PageCount {
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>
1067 private int PageIndexInternal {
1072 int currentPageIndex = PageIndexInternal;
1073 if (value != currentPageIndex) {
1076 RequiresDataBinding = true;
1084 /// <para>Gets or sets the index of the currently displayed record.</para>
1089 WebCategory("Data"),
1090 WebSysDescription(SR.DetailsView_PageIndex)
1092 public virtual int PageIndex {
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) {
1098 return PageIndexInternal;
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
1104 throw new ArgumentOutOfRangeException("value");
1107 PageIndexInternal = value;
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>
1119 WebCategory("Paging"),
1120 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1121 NotifyParentProperty(true),
1122 PersistenceMode(PersistenceMode.InnerProperty),
1123 WebSysDescription(SR.DetailsView_PagerSettings)
1125 public virtual PagerSettings PagerSettings {
1127 if (_pagerSettings == null) {
1128 _pagerSettings = new PagerSettings();
1129 if (IsTrackingViewState) {
1130 ((IStateManager)_pagerSettings).TrackViewState();
1132 _pagerSettings.PropertyChanged += new EventHandler(OnPagerPropertyChanged);
1134 return _pagerSettings;
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>
1145 WebCategory("Styles"),
1146 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1147 NotifyParentProperty(true),
1148 PersistenceMode(PersistenceMode.InnerProperty),
1149 WebSysDescription(SR.WebControl_PagerStyle)
1151 public TableItemStyle PagerStyle {
1153 if (_pagerStyle == null) {
1154 _pagerStyle = new TableItemStyle();
1155 if (IsTrackingViewState)
1156 ((IStateManager)_pagerStyle).TrackViewState();
1164 /// <para>Indicates the template to use for a pager item within the DetailsView.
1169 PersistenceMode(PersistenceMode.InnerProperty),
1170 TemplateContainer(typeof(DetailsView)),
1171 WebSysDescription(SR.View_PagerTemplate)
1173 public virtual ITemplate PagerTemplate {
1175 return _pagerTemplate;
1178 _pagerTemplate = value;
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>
1190 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1191 WebSysDescription(SR.DetailsView_Rows)
1193 public virtual DetailsViewRowCollection Rows {
1195 if (_rowsCollection == null) {
1196 if (_rowsArray == null) {
1197 EnsureChildControls();
1199 if (_rowsArray == null) {
1200 _rowsArray = new ArrayList();
1202 _rowsCollection = new DetailsViewRowCollection(_rowsArray);
1204 return _rowsCollection;
1211 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1213 public IAutoFieldGenerator RowsGenerator {
1215 return _rowsGenerator;
1218 _rowsGenerator = value;
1222 private IAutoFieldGenerator RowsGeneratorInternal {
1224 return RowsGenerator ?? _defaultRowsGenerator;
1230 /// <para>Indicates the style properties of each row.</para>
1233 WebCategory("Styles"),
1235 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1236 NotifyParentProperty(true),
1237 PersistenceMode(PersistenceMode.InnerProperty),
1238 WebSysDescription(SR.View_RowStyle)
1240 public TableItemStyle RowStyle {
1242 if (_rowStyle == null) {
1243 _rowStyle = new TableItemStyle();
1244 if (IsTrackingViewState)
1245 ((IStateManager)_rowStyle).TrackViewState();
1254 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1256 public object SelectedValue {
1258 return DataKey.Value;
1262 protected override HtmlTextWriterTag TagKey {
1264 return EnablePagingCallbacks ?
1265 HtmlTextWriterTag.Div : HtmlTextWriterTag.Table;
1272 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1274 public virtual DetailsViewRow TopPagerRow {
1276 if (_topPagerRow == null) {
1277 EnsureChildControls();
1279 return _topPagerRow;
1285 /// <para>Occurs when a command is issued from the DetailsView.</para>
1288 WebCategory("Action"),
1289 WebSysDescription(SR.DetailsView_OnItemCommand)
1291 public event DetailsViewCommandEventHandler ItemCommand {
1293 Events.AddHandler(EventItemCommand, value);
1296 Events.RemoveHandler(EventItemCommand, value);
1302 /// <para>Occurs when a row is created.</para>
1305 WebCategory("Behavior"),
1306 WebSysDescription(SR.DetailsView_OnItemCreated)
1308 public event EventHandler ItemCreated {
1310 Events.AddHandler(EventItemCreated, value);
1313 Events.RemoveHandler(EventItemCreated, value);
1319 /// <para>Occurs when the DetailsView item has been deleted.</para>
1322 WebCategory("Action"),
1323 WebSysDescription(SR.DataControls_OnItemDeleted)
1325 public event DetailsViewDeletedEventHandler ItemDeleted {
1327 Events.AddHandler(EventItemDeleted, value);
1330 Events.RemoveHandler(EventItemDeleted, value);
1336 /// <para>Occurs when the DetailsView item is being deleted.</para>
1339 WebCategory("Action"),
1340 WebSysDescription(SR.DataControls_OnItemDeleting)
1342 public event DetailsViewDeleteEventHandler ItemDeleting {
1344 Events.AddHandler(EventItemDeleting, value);
1347 Events.RemoveHandler(EventItemDeleting, value);
1353 /// <para>Occurs when the DetailsView item has been inserted.</para>
1356 WebCategory("Action"),
1357 WebSysDescription(SR.DataControls_OnItemInserted)
1359 public event DetailsViewInsertedEventHandler ItemInserted {
1361 Events.AddHandler(EventItemInserted, value);
1364 Events.RemoveHandler(EventItemInserted, value);
1370 /// <para>Occurs when the DetailsView item is being inserted.</para>
1373 WebCategory("Action"),
1374 WebSysDescription(SR.DataControls_OnItemInserting)
1376 public event DetailsViewInsertEventHandler ItemInserting {
1378 Events.AddHandler(EventItemInserting, value);
1381 Events.RemoveHandler(EventItemInserting, value);
1387 /// <para>Occurs when the DetailsView item has been updated.</para>
1390 WebCategory("Action"),
1391 WebSysDescription(SR.DataControls_OnItemUpdated)
1393 public event DetailsViewUpdatedEventHandler ItemUpdated {
1395 Events.AddHandler(EventItemUpdated, value);
1398 Events.RemoveHandler(EventItemUpdated, value);
1404 /// <para>Occurs when the DetailsView item is being updated.</para>
1407 WebCategory("Action"),
1408 WebSysDescription(SR.DataControls_OnItemUpdating)
1410 public event DetailsViewUpdateEventHandler ItemUpdating {
1412 Events.AddHandler(EventItemUpdating, value);
1415 Events.RemoveHandler(EventItemUpdating, value);
1421 /// <para>Occurs when the ViewMode has changed.</para>
1424 WebCategory("Action"),
1425 WebSysDescription(SR.DetailsView_OnModeChanged)
1427 public event EventHandler ModeChanged {
1429 Events.AddHandler(EventModeChanged, value);
1432 Events.RemoveHandler(EventModeChanged, value);
1438 /// <para>Occurs when the ViewMode is changing.</para>
1441 WebCategory("Action"),
1442 WebSysDescription(SR.DetailsView_OnModeChanging)
1444 public event DetailsViewModeEventHandler ModeChanging {
1446 Events.AddHandler(EventModeChanging, value);
1449 Events.RemoveHandler(EventModeChanging, value);
1455 /// <para>Occurs when the DetailsView PageIndex has been changed.</para>
1458 WebCategory("Action"),
1459 WebSysDescription(SR.DetailsView_OnPageIndexChanged)
1461 public event EventHandler PageIndexChanged {
1463 Events.AddHandler(EventPageIndexChanged, value);
1466 Events.RemoveHandler(EventPageIndexChanged, value);
1472 /// <para>Occurs when the DetailsView PageIndex is changing.</para>
1475 WebCategory("Action"),
1476 WebSysDescription(SR.DetailsView_OnPageIndexChanging)
1478 public event DetailsViewPageEventHandler PageIndexChanging {
1480 Events.AddHandler(EventPageIndexChanging, value);
1483 Events.RemoveHandler(EventPageIndexChanging, value);
1488 /// <para>Builds the callback argument used in DataControlLinkButtons.</para>
1490 private string BuildCallbackArgument(int pageIndex) {
1491 return "\"" + Convert.ToString(pageIndex, CultureInfo.InvariantCulture) + "|\"";
1495 public void ChangeMode(DetailsViewMode newMode) {
1500 /// Create a single autogenerated row. This function can be overridden to create a different AutoGeneratedField.
1502 protected virtual AutoGeneratedField CreateAutoGeneratedRow(AutoGeneratedFieldProperties fieldProperties) {
1503 AutoGeneratedField field = new AutoGeneratedField(fieldProperties.DataField);
1504 string name = fieldProperties.Name;
1505 ((IStateManager)field).TrackViewState();
1507 field.HeaderText = name;
1508 field.SortExpression = name;
1509 field.ReadOnly = fieldProperties.IsReadOnly;
1510 field.DataType = fieldProperties.Type;
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.
1522 protected virtual ICollection CreateAutoGeneratedRows(object dataItem) {
1523 return _defaultRowsGenerator.CreateAutoGeneratedFields(dataItem, this);
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>
1534 protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding) {
1535 PagedDataSource pagedDataSource = null;
1536 int itemIndex = PageIndex;
1537 bool allowPaging = AllowPaging;
1539 DetailsViewMode mode = Mode;
1541 // if we're in design mode, PageIndex doesn't return -1
1542 if (DesignMode && mode == DetailsViewMode.Insert) {
1547 DataSourceView view = GetData();
1548 DataSourceSelectArguments arguments = SelectArguments;
1551 throw new HttpException(SR.GetString(SR.DataBoundControl_NullView, ID));
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);
1565 if (_useServerPaging) {
1566 if (view.CanRetrieveTotalRowCount) {
1567 pagedDataSource = CreateServerPagedDataSource(arguments.TotalRowCount);
1570 ICollection dataSourceCollection = dataSource as ICollection;
1571 if (dataSourceCollection == null) {
1572 throw new HttpException(SR.GetString(SR.DataBoundControl_NeedICollectionOrTotalRowCount, GetType().Name));
1574 pagedDataSource = CreateServerPagedDataSource(checked(PageIndex + dataSourceCollection.Count));
1578 pagedDataSource = CreatePagedDataSource();
1583 pagedDataSource = CreatePagedDataSource();
1586 if (mode != DetailsViewMode.Insert) {
1587 pagedDataSource.DataSource = dataSource;
1590 IEnumerator dataSourceEnumerator = null;
1591 OrderedDictionary keyTable = KeyTable;
1593 _rowsArray = new ArrayList();
1594 _rowsCollection = null;
1596 if (dataBinding == false) {
1597 dataSourceEnumerator = dataSource.GetEnumerator();
1599 ICollection collection = dataSource as ICollection;
1600 if (collection == null) {
1601 throw new HttpException(SR.GetString(SR.DataControls_DataSourceMustBeCollectionWhenNotDataBinding));
1603 itemCount = collection.Count;
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));
1613 if (pagedDataSource.IsPagingEnabled) {
1614 itemCount = pagedDataSource.DataSourceCount;
1616 else if (collection != null) {
1617 itemCount = collection.Count;
1620 dataSourceEnumerator = dataSource.GetEnumerator();
1624 Table table = CreateTable();
1625 TableRowCollection rows = table.Rows;
1626 bool moveNextSucceeded = false;
1627 object lastItem = null;
1629 Controls.Add(table);
1631 if (dataSourceEnumerator != null) {
1632 moveNextSucceeded = dataSourceEnumerator.MoveNext(); // goto the first item
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));
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.
1661 if (moveNextSucceeded) {
1662 _dataItem = dataSourceEnumerator.Current;
1665 _dataItem = lastItem; // if we broke out of the above loop, the current item will be invalid
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) {
1675 moveNextSucceeded = dataSourceEnumerator.MoveNext();
1679 _dataItemIndex = currentItemIndex;
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) {
1684 _topPagerRow = CreateRow(-1, DataControlRowType.Pager, DataControlRowState.Normal, null, rows, pagedDataSource);
1687 _headerRow = CreateRow(-1, DataControlRowType.Header, DataControlRowState.Normal, null, rows, null);
1688 if (_headerTemplate == null && HeaderText.Length == 0) {
1689 _headerRow.Visible = false;
1692 _rowsArray.AddRange(CreateDataRows(dataBinding, rows, _dataItem));
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);
1701 _dataKey = new DataKey(keyTable);
1705 _footerRow = CreateRow(-1, DataControlRowType.Footer, DataControlRowState.Normal, null, rows, null);
1706 if (_footerTemplate == null && FooterText.Length == 0) {
1707 _footerRow.Visible = false;
1710 if (allowPaging && PagerSettings.Visible && _pagerSettings.IsPagerOnBottom && !singlePage && mode != DetailsViewMode.Insert) {
1712 _bottomPagerRow = CreateRow(-1, DataControlRowType.Pager, DataControlRowState.Normal, null, rows, pagedDataSource);
1716 _pageCount = itemCount;
1718 OnItemCreated(EventArgs.Empty);
1729 /// <para>Creates new control style.</para>
1731 protected override Style CreateControlStyle() {
1732 TableStyle controlStyle = new TableStyle();
1734 // initialize defaults that are different from TableStyle
1735 controlStyle.GridLines = GridLines.Both;
1736 controlStyle.CellSpacing = 0;
1738 return controlStyle;
1741 private ICollection CreateDataRows(bool dataBinding, TableRowCollection rows, object dataItem) {
1742 ArrayList rowsArray = new ArrayList();
1743 rowsArray.AddRange(CreateDataRowsFromFields(dataItem, dataBinding, rows));
1747 private ICollection CreateDataRowsFromFields(object dataItem, bool dataBinding, TableRowCollection rows) {
1749 ICollection fields = CreateFieldSet(dataItem, dataBinding);
1750 ArrayList rowsArray = new ArrayList();
1752 fieldCount = fields.Count;
1754 if (fieldCount > 0) {
1755 DataControlRowType rowType = DataControlRowType.DataRow;
1756 DataControlRowState masterRowState = DataControlRowState.Normal;
1757 int dataRowIndex = 0;
1758 DetailsViewMode mode = Mode;
1760 if (mode == DetailsViewMode.Edit)
1761 masterRowState |= DataControlRowState.Edit;
1762 else if (mode == DetailsViewMode.Insert)
1763 masterRowState |= DataControlRowState.Insert;
1765 bool requiresDataBinding = false;
1766 foreach (DataControlField field in fields) {
1767 if (field.Initialize(false, this)) {
1768 requiresDataBinding = true;
1770 if (DetermineRenderClientScript()) {
1771 field.ValidateSupportsCallback();
1774 DataControlRowState rowState = masterRowState;
1776 if (dataRowIndex % 2 != 0) {
1777 rowState |= DataControlRowState.Alternate;
1780 rowsArray.Add(CreateRow(dataRowIndex, rowType, rowState, field, rows, null));
1784 if (requiresDataBinding) {
1785 RequiresDataBinding = true;
1791 protected override DataSourceSelectArguments CreateDataSourceSelectArguments() {
1792 DataSourceSelectArguments arguments = new DataSourceSelectArguments();
1793 DataSourceView view = GetData();
1794 _useServerPaging = AllowPaging && view.CanPage;
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;
1804 arguments.MaximumRows = -1;
1813 /// Creates the set of fields to be used to build up the control
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
1819 protected virtual ICollection CreateFieldSet(object dataItem, bool useDataSource) {
1820 ArrayList fieldsArray = new ArrayList();
1822 if (AutoGenerateRows == true) {
1823 if (RowsGeneratorInternal is DetailsViewRowsGenerator) {
1824 ((DetailsViewRowsGenerator)RowsGeneratorInternal).DataItem = dataItem;
1825 ((DetailsViewRowsGenerator)RowsGeneratorInternal).InDataBinding = useDataSource;
1827 fieldsArray.AddRange(RowsGeneratorInternal.GenerateFields(this));
1830 foreach (DataControlField f in Fields) {
1834 if (AutoGenerateInsertButton || AutoGenerateDeleteButton || AutoGenerateEditButton) {
1835 CommandField commandField = new CommandField();
1836 commandField.ButtonType = ButtonType.Link;
1838 if (AutoGenerateInsertButton) {
1839 commandField.ShowInsertButton = true;
1842 if (AutoGenerateDeleteButton) {
1843 commandField.ShowDeleteButton = true;
1846 if (AutoGenerateEditButton) {
1847 commandField.ShowEditButton = true;
1849 fieldsArray.Add(commandField);
1856 /// Creates the pager for NextPrev and NextPrev with First and Last styles
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;
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));
1877 firstButton = new DataControlPagerLinkButton(this);
1878 ((DataControlPagerLinkButton)firstButton).Text = pagerSettings.FirstPageText;
1879 ((DataControlPagerLinkButton)firstButton).EnableCallback(BuildCallbackArgument(0));
1881 firstButton.CommandName = DataControlCommands.PageCommandName;
1882 firstButton.CommandArgument = DataControlCommands.FirstPageCommandArgument;
1883 cell.Controls.Add((Control)firstButton);
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));
1896 prevButton = new DataControlPagerLinkButton(this);
1897 ((DataControlPagerLinkButton)prevButton).Text = pagerSettings.PreviousPageText;
1898 ((DataControlPagerLinkButton)prevButton).EnableCallback(BuildCallbackArgument(PageIndex - 1));
1900 prevButton.CommandName = DataControlCommands.PageCommandName;
1901 prevButton.CommandArgument = DataControlCommands.PreviousPageCommandArgument;
1902 cell.Controls.Add((Control)prevButton);
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));
1916 nextButton = new DataControlPagerLinkButton(this);
1917 ((DataControlPagerLinkButton)nextButton).Text = pagerSettings.NextPageText;
1918 ((DataControlPagerLinkButton)nextButton).EnableCallback(BuildCallbackArgument(PageIndex + 1));
1920 nextButton.CommandName = DataControlCommands.PageCommandName;
1921 nextButton.CommandArgument = DataControlCommands.NextPageCommandArgument;
1922 cell.Controls.Add((Control)nextButton);
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));
1936 lastButton = new DataControlPagerLinkButton(this);
1937 ((DataControlPagerLinkButton)lastButton).Text = pagerSettings.LastPageText;
1938 ((DataControlPagerLinkButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
1940 lastButton.CommandName = DataControlCommands.PageCommandName;
1941 lastButton.CommandArgument = DataControlCommands.LastPageCommandArgument;
1942 cell.Controls.Add((Control)lastButton);
1947 /// Creates the pager for NextPrev and NextPrev with First and Last styles
1949 private void CreateNumericPager(TableRow row, PagedDataSource pagedDataSource, bool addFirstLastPageButtons) {
1950 PagerSettings pagerSettings = PagerSettings;
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
1958 // ensure the number of pages we show isn't more than the number of pages that do exist
1959 if (pages < pagesShown)
1962 // initialize to the first page set, i.e., pages 1 through number of pages shown
1964 int lastPage = pagesShown;
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;
1975 firstPage = currentPageSet * pageSetSize + 1;
1977 lastPage = firstPage + pageSetSize - 1;
1979 // now bring back lastPage into the range if its exceeded the number of pages
1980 if (lastPage > pages)
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);
1988 FirstDisplayedPageIndex = firstPage - 1;
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);
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));
2005 firstButton = new DataControlPagerLinkButton(this);
2006 ((DataControlPagerLinkButton)firstButton).Text = pagerSettings.FirstPageText;
2007 ((DataControlPagerLinkButton)firstButton).EnableCallback(BuildCallbackArgument(0));
2009 firstButton.CommandName = DataControlCommands.PageCommandName;
2010 firstButton.CommandArgument = DataControlCommands.FirstPageCommandArgument;
2011 cell.Controls.Add((Control)firstButton);
2014 if (firstPage != 1) {
2015 TableCell cell = new TableCell();
2016 row.Cells.Add(cell);
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);
2026 for (int i = firstPage; i <= lastPage; i++) {
2027 TableCell cell = new TableCell();
2028 row.Cells.Add(cell);
2030 string pageString = (i).ToString(NumberFormatInfo.InvariantInfo);
2031 if (i == currentPage) {
2032 Label label = new Label();
2034 label.Text = pageString;
2035 cell.Controls.Add(label);
2037 button = new DataControlPagerLinkButton(this);
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);
2047 if (pages > lastPage) {
2048 TableCell cell = new TableCell();
2049 row.Cells.Add(cell);
2050 button = new DataControlPagerLinkButton(this);
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);
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);
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));
2072 lastButton = new DataControlPagerLinkButton(this);
2073 ((DataControlPagerLinkButton)lastButton).Text = pagerSettings.LastPageText;
2074 ((DataControlPagerLinkButton)lastButton).EnableCallback(BuildCallbackArgument(pagedDataSource.PageCount - 1));
2076 lastButton.CommandName = DataControlCommands.PageCommandName;
2077 lastButton.CommandArgument = DataControlCommands.LastPageCommandArgument;
2078 cell.Controls.Add((Control)lastButton);
2082 private PagedDataSource CreatePagedDataSource() {
2083 PagedDataSource pagedDataSource = new PagedDataSource();
2085 pagedDataSource.CurrentPageIndex = PageIndex;
2086 pagedDataSource.PageSize = 1;
2087 pagedDataSource.AllowPaging = AllowPaging;
2088 pagedDataSource.AllowCustomPaging = false;
2089 pagedDataSource.AllowServerPaging = false;
2090 pagedDataSource.VirtualCount = 0;
2092 return pagedDataSource;
2095 private PagedDataSource CreateServerPagedDataSource(int totalRowCount) {
2096 PagedDataSource pagedDataSource = new PagedDataSource();
2098 pagedDataSource.CurrentPageIndex = PageIndex;
2099 pagedDataSource.PageSize = 1;
2100 pagedDataSource.AllowPaging = AllowPaging;
2101 pagedDataSource.AllowCustomPaging = false;
2102 pagedDataSource.AllowServerPaging = true;
2103 pagedDataSource.VirtualCount = totalRowCount;
2105 return pagedDataSource;
2108 private DetailsViewRow CreateRow(int rowIndex, DataControlRowType rowType, DataControlRowState rowState, DataControlField field, TableRowCollection rows, PagedDataSource pagedDataSource) {
2109 DetailsViewRow row = CreateRow(rowIndex, rowType, rowState);
2112 if (rowType != DataControlRowType.Pager) {
2113 InitializeRow(row, field);
2115 InitializePager(row, pagedDataSource);
2123 /// <para>[To be supplied.]</para>
2125 protected virtual DetailsViewRow CreateRow(int rowIndex, DataControlRowType rowType, DataControlRowState rowState) {
2126 if (rowType == DataControlRowType.Pager) {
2127 return new DetailsViewPagerRow(rowIndex, rowType, rowState);
2129 return new DetailsViewRow(rowIndex, rowType, rowState);
2134 /// Creates a new Table, which is the containing table
2136 protected virtual Table CreateTable() {
2137 return new ChildTable(String.IsNullOrEmpty(ID) ? null : ClientID);
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() {
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);
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.
2160 if (!_renderClientScriptValid) {
2161 _renderClientScript = false;
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;
2170 _renderClientScriptValid = true;
2172 return _renderClientScript;
2176 /// Override EnsureDataBound because we don't want to databind when we're in insert mode
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);
2183 RequiresDataBinding = false;
2185 if (AdapterInternal != null) {
2186 DataBoundControlAdapter dataBoundControlAdapter = AdapterInternal as DataBoundControlAdapter;
2187 if(dataBoundControlAdapter != null) {
2188 dataBoundControlAdapter.PerformDataBinding(null);
2191 PerformDataBinding(null);
2195 PerformDataBinding(null);
2198 OnDataBound(EventArgs.Empty);
2201 base.EnsureDataBound();
2205 internal static void ExtractRowValues(object[] fields, DetailsViewRowCollection rows, string[] dataKeyNames, IOrderedDictionary fieldValues, bool includeReadOnlyFields, bool includeKeys) {
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) {
2215 if (((DataControlField)fields[i]).ShowHeader) {
2219 if (!((DataControlField)fields[i]).Visible) {
2223 OrderedDictionary newValues = new OrderedDictionary();
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;
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.");
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;
2247 ExtractRowValues(fields, rows, DataKeyNamesInternal, fieldValues, includeReadOnlyFields, includeKeys);
2250 protected virtual string GetCallbackResult() {
2251 StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
2253 HtmlTextWriter writer = new HtmlTextWriter(stringWriter);
2254 IStateFormatter2 formatter = Page.CreateStateFormatter();
2256 RenderTableContents(writer);
2261 object dataKeyState = OrderedDictionaryStateHelper.SaveViewState(KeyTable);
2262 string dataKeyString = formatter.Serialize(dataKeyState, Purpose.WebForms_DetailsView_KeyTable);
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();
2268 protected virtual string GetCallbackScript(IButtonControl buttonControl, string argument) {
2269 if (DetermineRenderClientScript()) {
2270 if (!String.IsNullOrEmpty(argument)) {
2272 Page.ClientScript.RegisterForEventValidation(UniqueID, argument);
2275 string clientCallbackReference = "javascript:__dv" + ClientID + ".callback";
2276 return clientCallbackReference + "(" + argument + "); return false;";
2282 private void HandleCancel() {
2283 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2285 DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DefaultMode, true);
2292 if (isBoundToDataSourceControl) {
2294 OnModeChanged(EventArgs.Empty);
2297 RequiresDataBinding = true;
2300 private void HandleDelete(string commandArg) {
2301 int pageIndex = PageIndex;
2302 if (pageIndex < 0) { // don't attempt to delete in Insert mode
2306 DataSourceView view = null;
2307 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2309 if (isBoundToDataSourceControl) {
2312 throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2316 DetailsViewDeleteEventArgs e = new DetailsViewDeleteEventArgs(pageIndex);
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);
2334 if (isBoundToDataSourceControl) {
2335 _deleteKeys = e.Keys;
2336 _deleteValues = e.Values;
2337 view.Delete(e.Keys, e.Values, HandleDeleteCallback);
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);
2350 _deleteValues = null;
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()) {
2361 if (pageIndex == _pageCount - 1) {
2362 HandlePage(pageIndex - 1);
2365 RequiresDataBinding = true;
2369 private void HandleEdit() {
2370 if (PageIndex < 0) {
2374 DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Edit, false);
2381 if (IsDataBindingAutomatic) {
2383 OnModeChanged(EventArgs.Empty);
2386 RequiresDataBinding = true;
2389 private bool HandleEvent(EventArgs e, bool causesValidation, string validationGroup) {
2390 bool handled = false;
2392 ResetModelValidationGroup(causesValidation, validationGroup);
2394 DetailsViewCommandEventArgs dce = e as DetailsViewCommandEventArgs;
2404 string command = dce.CommandName;
2405 int newItemIndex = PageIndex;
2407 if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.PageCommandName)) {
2408 string itemIndexArg = (string)dce.CommandArgument;
2410 if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.NextPageCommandArgument)) {
2412 } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.PreviousPageCommandArgument)) {
2414 } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.FirstPageCommandArgument)) {
2416 } else if (StringUtil.EqualsIgnoreCase(itemIndexArg, DataControlCommands.LastPageCommandArgument)) {
2417 newItemIndex = PageCount - 1;
2419 // argument is page number, and page index is 1 less than that
2420 newItemIndex = Convert.ToInt32(itemIndexArg, CultureInfo.InvariantCulture) - 1;
2422 HandlePage(newItemIndex);
2423 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.EditCommandName)) {
2425 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.UpdateCommandName)) {
2426 HandleUpdate((string)dce.CommandArgument, causesValidation);
2427 } else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.CancelCommandName)) {
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);
2434 else if (StringUtil.EqualsIgnoreCase(command, DataControlCommands.NewCommandName)) {
2438 handled = HandleCommand(command);
2445 private bool HandleCommand(string commandName) {
2446 DataSourceView view = null;
2448 if (IsDataBindingAutomatic) {
2451 throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2458 if (!view.CanExecute(commandName)) {
2462 OrderedDictionary values = new OrderedDictionary();
2463 OrderedDictionary keys = new OrderedDictionary();
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);
2473 view.ExecuteCommand(commandName, keys, values, HandleCommandCallback);
2477 private bool HandleCommandCallback(int affectedRows, Exception ex) {
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()) {
2487 RequiresDataBinding = true;
2491 private void HandleInsert(string commandArg, bool causesValidation) {
2492 if (causesValidation && Page != null && !Page.IsValid) {
2496 if (Mode != DetailsViewMode.Insert) {
2497 throw new HttpException(SR.GetString(SR.DetailsViewFormView_ControlMustBeInInsertMode, "DetailsView", ID));
2500 DataSourceView view = null;
2501 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2503 if (isBoundToDataSourceControl) {
2506 throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2510 DetailsViewInsertEventArgs e = new DetailsViewInsertEventArgs(commandArg);
2513 ExtractRowValues(e.Values, false/*includeReadOnlyFields*/, true/*includePrimaryKey*/);
2522 if (isBoundToDataSourceControl) {
2523 _insertValues = e.Values;
2524 view.Insert(e.Values, HandleInsertCallback);
2528 private bool HandleInsertCallback(int affectedRows, Exception ex) {
2529 DetailsViewInsertedEventArgs dea = new DetailsViewInsertedEventArgs(affectedRows, ex);
2530 dea.SetValues(_insertValues);
2531 OnItemInserted(dea);
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()) {
2541 dea.KeepInInsertMode = true;
2544 if (IsUsingModelBinders && !Page.ModelState.IsValid) {
2545 dea.KeepInInsertMode = true;
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;
2560 private void HandleNew() {
2561 DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Insert, false);
2568 if (IsDataBindingAutomatic) {
2570 OnModeChanged(EventArgs.Empty);
2573 RequiresDataBinding = true;
2576 private void HandlePage(int newPage) {
2581 if (PageIndex < 0) {
2585 DetailsViewPageEventArgs e = new DetailsViewPageEventArgs(newPage);
2586 OnPageIndexChanging(e);
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)) {
2598 // DevDiv Bugs 188830: Don't clear key table if page is out of range, since control won't be rebound.
2600 _pageIndex = e.NewPageIndex;
2607 OnPageIndexChanged(EventArgs.Empty);
2608 RequiresDataBinding = true;
2611 private void HandleUpdate(string commandArg, bool causesValidation) {
2612 if (causesValidation && Page != null && !Page.IsValid) {
2616 if (Mode != DetailsViewMode.Edit) {
2617 throw new HttpException(SR.GetString(SR.DetailsViewFormView_ControlMustBeInEditMode, "DetailsView", ID));
2620 if (PageIndex < 0) {
2624 DataSourceView view = null;
2625 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
2627 if (isBoundToDataSourceControl) {
2630 throw new HttpException(SR.GetString(SR.View_DataSourceReturnedNullView, ID));
2634 DetailsViewUpdateEventArgs e = new DetailsViewUpdateEventArgs(commandArg);
2637 foreach (DictionaryEntry entry in BoundFieldValues) {
2638 e.OldValues.Add(entry.Key, entry.Value);
2641 ExtractRowValues(e.NewValues, false/*includeReadOnlyFields*/, true/*includePrimaryKey*/);
2642 foreach (DictionaryEntry entry in DataKey.Values) {
2643 e.Keys.Add(entry.Key, entry.Value);
2654 if (isBoundToDataSourceControl) {
2655 _updateKeys = e.Keys;
2656 _updateNewValues = e.NewValues;
2657 _updateOldValues = e.OldValues;
2659 view.Update(e.Keys, e.NewValues, e.OldValues, HandleUpdateCallback);
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);
2672 _updateOldValues = null;
2673 _updateNewValues = null;
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()) {
2682 dea.KeepInEditMode = true;
2685 if (IsUsingModelBinders && !Page.ModelState.IsValid) {
2686 dea.KeepInEditMode = true;
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;
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.
2709 protected virtual void InitializePager(DetailsViewRow row, PagedDataSource pagedDataSource) {
2710 TableCell cell = new TableCell();
2712 PagerSettings pagerSettings = PagerSettings;
2714 if (_pagerTemplate != null) {
2715 _pagerTemplate.InstantiateIn(cell);
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);
2726 case PagerButtons.Numeric:
2727 CreateNumericPager(pagerTableRow, pagedDataSource, false);
2729 case PagerButtons.NextPreviousFirstLast:
2730 CreateNextPrevPager(pagerTableRow, pagedDataSource, true);
2732 case PagerButtons.NumericFirstLast:
2733 CreateNumericPager(pagerTableRow, pagedDataSource, true);
2737 cell.ColumnSpan = 2;
2738 row.Cells.Add(cell);
2744 /// <para>[To be supplied.]</para>
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;
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);
2761 contentCell.ColumnSpan = 2;
2763 field.InitializeCell(contentCell, DataControlCellType.DataCell, rowState, itemIndex);
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;
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;
2781 case DataControlRowType.EmptyDataRow:
2782 contentTemplate = _emptyDataTemplate;
2783 string emptyDataText = EmptyDataText;
2784 if (_emptyDataTemplate == null && emptyDataText.Length > 0) {
2785 contentCell.Text = emptyDataText;
2790 if (contentTemplate != null) {
2791 contentTemplate.InstantiateIn(contentCell);
2793 cells.Add(contentCell);
2796 public virtual void InsertItem(bool causesValidation) {
2797 ResetModelValidationGroup(causesValidation, String.Empty);
2798 HandleInsert(String.Empty, causesValidation);
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.
2807 public virtual bool IsBindableType(Type type) {
2808 return DataBoundControlHelper.IsBindableType(type, enableEnums: RenderingCompatibility >= VersionUtil.Framework45);
2813 /// <para>Loads the control state for those properties that should persist across postbacks
2814 /// even when EnableViewState=false.</para>
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.
2821 _defaultMode = DetailsViewMode.ReadOnly;
2822 _dataKeyNames = new string[0];
2825 object[] state = savedState as object[];
2827 if (state != null) {
2828 base.LoadControlState(state[0]);
2829 if (state[1] != null) {
2830 _pageIndex = (int)state[1];
2833 if (state[2] != null) {
2834 _defaultMode = (DetailsViewMode)state[2];
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];
2843 if (state[4] != null) {
2844 _dataKeyNames = (string[])state[4];
2847 if (state[5] != null) {
2849 OrderedDictionaryStateHelper.LoadViewState((OrderedDictionary)KeyTable, (ArrayList)state[5]);
2852 if (state[6] != null) {
2853 _pageCount = (int)state[6];
2857 base.LoadControlState(null);
2862 private bool LoadHiddenFieldState(string pageIndex, string dataKey) {
2863 bool propertyChanged = false;
2864 int oldPageIndex = Int32.Parse(pageIndex, CultureInfo.InvariantCulture);
2866 if (PageIndex != oldPageIndex) {
2867 propertyChanged = true;
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;
2873 string oldDataKeyString = dataKey;
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) {
2881 OrderedDictionaryStateHelper.LoadViewState(KeyTable, oldDataKeyState);
2884 return propertyChanged;
2889 /// <para>Loads a saved state of the <see cref='System.Web.UI.WebControls.DetailsView'/>.</para>
2891 protected override void LoadViewState(object savedState) {
2892 if (savedState != null) {
2893 object[] myState = (object[])savedState;
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]);
2928 base.LoadViewState(null);
2935 protected override bool OnBubbleEvent(object source, EventArgs e) {
2936 bool causesValidation = false;
2937 string validationGroup = String.Empty;
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;
2947 return HandleEvent(e, causesValidation, validationGroup);
2950 protected override void OnDataSourceViewChanged(object sender, EventArgs e) {
2952 base.OnDataSourceViewChanged(sender, e);
2955 private void OnFieldsChanged(object sender, EventArgs e) {
2957 RequiresDataBinding = true;
2963 /// DetailsView initialization.
2965 protected internal override void OnInit(EventArgs e) {
2969 if (DataKeyNames.Length > 0 && !AutoGenerateRows) {
2970 Page.RegisterRequiresViewStateEncryption();
2972 Page.RegisterRequiresControlState(this);
2975 if (!DesignMode && !String.IsNullOrEmpty(ItemType)) {
2976 DataBoundControlHelper.EnableDynamicData(this, ItemType);
2982 /// <para>Raises the <see langword='ItemCommand'/> event.</para>
2984 protected virtual void OnItemCommand(DetailsViewCommandEventArgs e) {
2985 DetailsViewCommandEventHandler handler = (DetailsViewCommandEventHandler)Events[EventItemCommand];
2986 if (handler != null) {
2993 /// <para>Raises the <see langword='ItemCreated'/> event.</para>
2995 protected virtual void OnItemCreated(EventArgs e) {
2996 EventHandler handler = (EventHandler)Events[EventItemCreated];
2997 if (handler != null) {
3004 /// <para>Raises the <see langword='ItemDeleted '/>event.</para>
3006 protected virtual void OnItemDeleted(DetailsViewDeletedEventArgs e) {
3007 DetailsViewDeletedEventHandler handler = (DetailsViewDeletedEventHandler)Events[EventItemDeleted];
3008 if (handler != null) handler(this, e);
3013 /// <para>Raises the <see langword='Delete'/> event.</para>
3015 protected virtual void OnItemDeleting(DetailsViewDeleteEventArgs e) {
3016 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3018 DetailsViewDeleteEventHandler handler = (DetailsViewDeleteEventHandler)Events[EventItemDeleting];
3019 if (handler != null) {
3022 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3023 throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemDeleting"));
3030 /// <para>Raises the <see langword='ItemInserted '/>event.</para>
3032 protected virtual void OnItemInserted(DetailsViewInsertedEventArgs e) {
3033 DetailsViewInsertedEventHandler handler = (DetailsViewInsertedEventHandler)Events[EventItemInserted];
3034 if (handler != null) handler(this, e);
3039 /// <para>Raises the <see langword='Insert'/> event.</para>
3041 protected virtual void OnItemInserting(DetailsViewInsertEventArgs e) {
3042 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3044 DetailsViewInsertEventHandler handler = (DetailsViewInsertEventHandler)Events[EventItemInserting];
3045 if (handler != null) {
3048 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3049 throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemInserting"));
3056 /// <para>Raises the <see langword='ItemUpdated '/>event.</para>
3058 protected virtual void OnItemUpdated(DetailsViewUpdatedEventArgs e) {
3059 DetailsViewUpdatedEventHandler handler = (DetailsViewUpdatedEventHandler)Events[EventItemUpdated];
3060 if (handler != null) handler(this, e);
3065 /// <para>Raises the <see langword='Update'/> event.</para>
3067 protected virtual void OnItemUpdating(DetailsViewUpdateEventArgs e) {
3068 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3070 DetailsViewUpdateEventHandler handler = (DetailsViewUpdateEventHandler)Events[EventItemUpdating];
3071 if (handler != null) {
3074 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3075 throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ItemUpdating"));
3082 /// <para>Raises the <see langword='ModeChanged'/>event.</para>
3084 protected virtual void OnModeChanged(EventArgs e) {
3085 EventHandler handler = (EventHandler)Events[EventModeChanged];
3086 if (handler != null) handler(this, e);
3091 /// <para>Raises the <see langword='ModeChanging'/> event.</para>
3093 protected virtual void OnModeChanging(DetailsViewModeEventArgs e) {
3094 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3096 DetailsViewModeEventHandler handler = (DetailsViewModeEventHandler)Events[EventModeChanging];
3097 if (handler != null) {
3100 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3101 throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "ModeChanging"));
3107 /// <para>Raises the <see langword='PageIndexChanged'/>event.</para>
3109 protected virtual void OnPageIndexChanged(EventArgs e) {
3110 EventHandler handler = (EventHandler)Events[EventPageIndexChanged];
3111 if (handler != null) handler(this, e);
3116 /// <para>Raises the <see langword='ModeChanging'/> event.</para>
3118 protected virtual void OnPageIndexChanging(DetailsViewPageEventArgs e) {
3119 bool isBoundToDataSourceControl = IsDataBindingAutomatic;
3121 DetailsViewPageEventHandler handler = (DetailsViewPageEventHandler)Events[EventPageIndexChanging];
3122 if (handler != null) {
3125 if (isBoundToDataSourceControl == false && e.Cancel == false) {
3126 throw new HttpException(SR.GetString(SR.DetailsView_UnhandledEvent, ID, "PageIndexChanging"));
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;
3145 base.OnPagePreLoad(sender, e);
3148 private void OnPagerPropertyChanged(object sender, EventArgs e) {
3150 RequiresDataBinding = true;
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) {{
3165 /// <para>Sets up the callback scripts if client script is supported on the client</para>
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;
3173 scriptOM.RegisterClientScriptResource(typeof(DetailsView), "DetailsView.js");
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);
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);
3184 string startupScript = String.Format(CultureInfo.InvariantCulture, startupScriptFormat, clientReference, hiddenFieldID, doCallBackCall, PageIndex);
3185 scriptOM.RegisterStartupScript(typeof(DetailsView), clientReference, startupScript, true);
3189 private bool PageIsValidAfterModelException() {
3190 if (_modelValidationGroup == null) {
3193 Page.Validate(_modelValidationGroup);
3194 return Page.IsValid;
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>
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]);
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*/);
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) {
3226 Debug.Assert(Controls[0] is Table);
3228 Table childTable = (Table)Controls[0];
3229 childTable.CopyBaseAttributes(this);
3230 if (ControlStyleCreated && !ControlStyle.IsEmpty) {
3231 childTable.ApplyStyle(ControlStyle);
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
3238 childTable.GridLines = GridLines.Both;
3239 childTable.CellSpacing = 0;
3241 childTable.Caption = Caption;
3242 childTable.CaptionAlign = CaptionAlign;
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);
3253 Style compositeStyle;
3255 TableRowCollection rows = childTable.Rows;
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;
3264 if (headerFieldCell != null) {
3265 field = headerFieldCell.ContainingField;
3269 case DataControlRowType.Header:
3270 compositeStyle = _headerStyle;
3273 case DataControlRowType.Footer:
3274 compositeStyle = _footerStyle;
3277 case DataControlRowType.DataRow:
3278 compositeStyle.CopyFrom(_rowStyle);
3281 if ((rowState & DataControlRowState.Alternate) != 0) {
3282 compositeStyle.CopyFrom(altRowStyle);
3284 if (field is ButtonFieldBase) {
3285 compositeStyle.CopyFrom(_commandRowStyle);
3288 if ((rowState & DataControlRowState.Edit) != 0) {
3289 compositeStyle.CopyFrom(_editRowStyle);
3291 if ((rowState & DataControlRowState.Insert) != 0) {
3292 if (_insertRowStyle != null) {
3293 compositeStyle.CopyFrom(_insertRowStyle);
3296 compositeStyle.CopyFrom(_editRowStyle);
3301 case DataControlRowType.Pager:
3302 compositeStyle = _pagerStyle;
3304 case DataControlRowType.EmptyDataRow:
3305 compositeStyle = _emptyDataRowStyle;
3309 if (compositeStyle != null && row.Visible) {
3310 row.MergeStyle(compositeStyle);
3313 if (rowType == DataControlRowType.DataRow && field != null) {
3314 if (!field.Visible ||
3315 (Mode == DetailsViewMode.Insert && !field.InsertVisible)) {
3316 row.Visible = false;
3319 int contentCellIndex = 0;
3320 DataControlFieldCell contentFieldCell = null;
3322 if (headerFieldCell != null && headerFieldCell.ContainingField.ShowHeader) {
3323 headerFieldCell.MergeStyle(field.HeaderStyleInternal);
3324 headerFieldCell.MergeStyle(_fieldHeaderStyle);
3325 contentCellIndex = 1;
3327 contentFieldCell = row.Cells[contentCellIndex] as DataControlFieldCell;
3328 if (contentFieldCell != null) {
3329 contentFieldCell.MergeStyle(field.ItemStyleInternal);
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);
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");
3348 ValidateEvent(UniqueID, "\"" + arguments[0] + "|" + arguments[1] + "\"");
3350 LoadHiddenFieldState(arguments[2], arguments[3]);
3352 int pageNumber = Int32.Parse(arguments[0], CultureInfo.InvariantCulture);
3353 _pageIndex = pageNumber;
3358 protected virtual void RaisePostBackEvent(string eventArgument) {
3359 ValidateEvent(UniqueID, eventArgument);
3361 int separatorIndex = eventArgument.IndexOf('$');
3362 if (separatorIndex < 0) {
3366 CommandEventArgs cea = new CommandEventArgs(eventArgument.Substring(0, separatorIndex), eventArgument.Substring(separatorIndex + 1));
3368 DetailsViewCommandEventArgs dvcea = new DetailsViewCommandEventArgs(this, cea);
3369 HandleEvent(dvcea, false, String.Empty);
3374 /// <para>Displays the control on the client.</para>
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);
3382 private void Render(HtmlTextWriter writer, bool renderPanel) {
3384 Page.VerifyRenderingInServerForm(this);
3386 PrepareControlHierarchy();
3388 if (DetermineRenderClientScript()) {
3389 string clientID = ClientID;
3390 if (clientID == null) {
3391 throw new HttpException(SR.GetString(SR.DetailsView_MustBeParented));
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);
3400 writer.RenderBeginTag(HtmlTextWriterTag.Div);
3402 RenderContents(writer);
3404 writer.RenderEndTag();
3408 private void RenderTableContents(HtmlTextWriter writer) {
3409 Render(writer, false);
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;
3423 /// <para>Saves the control state for those properties that should persist across postbacks
3424 /// even when EnableViewState=false.</para>
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 ||
3432 _mode != _defaultMode ||
3433 _defaultMode != DetailsViewMode.ReadOnly ||
3434 (_dataKeyNames != null && _dataKeyNames.Length > 0) ||
3435 (_keyTable != null && _keyTable.Count > 0) ||
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;
3446 if (_pageIndex != 0) {
3447 pageIndexState = _pageIndex;
3449 if (_defaultMode != DetailsViewMode.ReadOnly) {
3450 defaultModeState = (int)_defaultMode;
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;
3458 if (_dataKeyNames != null && _dataKeyNames.Length > 0) {
3459 keyNamesState = _dataKeyNames;
3462 if (_keyTable != null) {
3463 keyTableState = OrderedDictionaryStateHelper.SaveViewState(_keyTable);
3466 if (_pageCount != 0) {
3467 pageCountState = _pageCount;
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;
3480 return true; // return a dummy that ensures LoadControlState gets called but minimizes persisted size.
3485 /// <para>Saves the current state of the <see cref='System.Web.UI.WebControls.DetailsView'/>.</para>
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;
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;
3520 // note that we always have some state, atleast the RowCount
3524 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
3525 Justification = "A property already exists. This method does additional work.")]
3526 public void SetPageIndex(int index) {
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));
3537 /// <para>Marks the starting point to begin tracking and saving changes to the
3538 /// control as part of the control viewstate.</para>
3540 protected override void TrackViewState() {
3541 base.TrackViewState();
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();
3567 public virtual void UpdateItem(bool causesValidation) {
3568 ResetModelValidationGroup(causesValidation, String.Empty);
3569 HandleUpdate(String.Empty, causesValidation);
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);
3578 #region IPostBackEventHandler implementation
3579 void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
3580 RaisePostBackEvent(eventArgument);
3584 #region IPostBackContainer implementation
3585 PostBackOptions IPostBackContainer.GetPostBackOptions(IButtonControl buttonControl) {
3586 if (buttonControl == null) {
3587 throw new ArgumentNullException("buttonControl");
3590 if (buttonControl.CausesValidation) {
3591 throw new InvalidOperationException(SR.GetString(SR.CannotUseParentPostBackWhenValidating, this.GetType().Name, ID));
3594 PostBackOptions options = new PostBackOptions(this, (buttonControl.CommandName + "$" + buttonControl.CommandArgument));
3595 options.RequiresJavaScriptProtocol = true;
3601 #region ICallbackContainer implementation
3602 string ICallbackContainer.GetCallbackScript(IButtonControl buttonControl, string argument) {
3603 return GetCallbackScript(buttonControl, argument);
3607 #region ICallbackEventHandler implementation
3608 void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument) {
3609 RaiseCallbackEvent(eventArgument);
3612 // The return value of this function is the argument to the callback handler in
3613 // GetCallbackEventReference.
3614 string ICallbackEventHandler.GetCallbackResult() {
3615 return GetCallbackResult();
3619 #region IDataItemContainer implementation
3620 int IDataItemContainer.DataItemIndex {
3622 return DataItemIndex;
3626 int IDataItemContainer.DisplayIndex {
3633 #region IDataBoundItemControl implementation
3635 DataKey IDataBoundItemControl.DataKey {
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 {
3646 case DetailsViewMode.Edit:
3647 return DataBoundControlMode.Edit;
3648 case DetailsViewMode.Insert:
3649 return DataBoundControlMode.Insert;
3650 case DetailsViewMode.ReadOnly:
3651 return DataBoundControlMode.ReadOnly;
3653 Debug.Fail("Shouldn't get here!");
3654 return DataBoundControlMode.ReadOnly;
3659 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3660 string IDataBoundControl.DataSourceID {
3662 return DataSourceID;
3665 DataSourceID = value;
3669 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3670 IDataSource IDataBoundControl.DataSourceObject {
3672 return DataSourceObject;
3676 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3677 object IDataBoundControl.DataSource {
3686 string[] IDataBoundControl.DataKeyNames {
3688 return DataKeyNames;
3691 DataKeyNames = value;
3695 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The property is accessible through the DataBoundControl")]
3696 string IDataBoundControl.DataMember {
3707 #region IFieldControl implementation
3709 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
3710 Justification = "The underlying implementation is not meant to be overridden.")]
3711 IAutoFieldGenerator IFieldControl.FieldsGenerator {
3713 return RowsGenerator;
3716 RowsGenerator = value;