New tests.
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / FormView.cs
index d12d91a1b8aa9add760605947fed4118f0239792..099ceb54126870937b3078e7a62e0b4d90078923 100644 (file)
@@ -71,6 +71,7 @@ namespace System.Web.UI.WebControls
                
                PropertyDescriptor[] cachedKeyProperties;
                readonly string[] emptyKeys = new string[0];
+               readonly string unhandledEventExceptionMessage = "The FormView '{0}' fired event {1} which wasn't handled.";
                
                // View state
                PagerSettings pagerSettings;
@@ -83,32 +84,28 @@ namespace System.Web.UI.WebControls
                TableItemStyle pagerStyle;
                TableItemStyle rowStyle;
                
+               IOrderedDictionary _keyTable;
                DataKey key;
                DataKey oldEditValues;
                
-               private static readonly object PageIndexChangedEvent = new object();
-               private static readonly object PageIndexChangingEvent = new object();
-               private static readonly object ItemCommandEvent = new object();
-               private static readonly object ItemCreatedEvent = new object();
-               private static readonly object ItemDeletedEvent = new object();
-               private static readonly object ItemDeletingEvent = new object();
-               private static readonly object ItemInsertedEvent = new object();
-               private static readonly object ItemInsertingEvent = new object();
-               private static readonly object ModeChangingEvent = new object();
-               private static readonly object ModeChangedEvent = new object();
-               private static readonly object ItemUpdatedEvent = new object();
-               private static readonly object ItemUpdatingEvent = new object();
+               static readonly object PageIndexChangedEvent = new object();
+               static readonly object PageIndexChangingEvent = new object();
+               static readonly object ItemCommandEvent = new object();
+               static readonly object ItemCreatedEvent = new object();
+               static readonly object ItemDeletedEvent = new object();
+               static readonly object ItemDeletingEvent = new object();
+               static readonly object ItemInsertedEvent = new object();
+               static readonly object ItemInsertingEvent = new object();
+               static readonly object ModeChangingEvent = new object();
+               static readonly object ModeChangedEvent = new object();
+               static readonly object ItemUpdatedEvent = new object();
+               static readonly object ItemUpdatingEvent = new object();
                
                // Control state
                int pageIndex;
                FormViewMode currentMode = FormViewMode.ReadOnly; 
                bool hasCurrentMode;
-               int pageCount = 0;
-               
-               public FormView ()
-               {
-                       key = new DataKey (new OrderedDictionary ());
-               }
+               int pageCount;
                
                public event EventHandler PageIndexChanged {
                        add { Events.AddHandler (PageIndexChangedEvent, value); }
@@ -182,8 +179,13 @@ namespace System.Web.UI.WebControls
                {
                        if (Events != null) {
                                FormViewPageEventHandler eh = (FormViewPageEventHandler) Events [PageIndexChangingEvent];
-                               if (eh != null) eh (this, e);
+                               if (eh != null) {
+                                       eh (this, e);
+                                       return;
+                               }
                        }
+                       if (!IsBoundUsingDataSourceID)
+                               throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "PageIndexChanging"));
                }
                
                protected virtual void OnItemCommand (FormViewCommandEventArgs e)
@@ -222,16 +224,26 @@ namespace System.Web.UI.WebControls
                {
                        if (Events != null) {
                                FormViewInsertEventHandler eh = (FormViewInsertEventHandler) Events [ItemInsertingEvent];
-                               if (eh != null) eh (this, e);
+                               if (eh != null) {
+                                       eh (this, e);
+                                       return;
+                               }
                        }
+                       if (!IsBoundUsingDataSourceID)
+                               throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemInserting"));
                }
                
                protected virtual void OnItemDeleting (FormViewDeleteEventArgs e)
                {
                        if (Events != null) {
                                FormViewDeleteEventHandler eh = (FormViewDeleteEventHandler) Events [ItemDeletingEvent];
-                               if (eh != null) eh (this, e);
+                               if (eh != null) {
+                                       eh (this, e);
+                                       return;
+                               }
                        }
+                       if (!IsBoundUsingDataSourceID)
+                               throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemDeleting"));
                }
                
                protected virtual void OnModeChanged (EventArgs e)
@@ -246,8 +258,13 @@ namespace System.Web.UI.WebControls
                {
                        if (Events != null) {
                                FormViewModeEventHandler eh = (FormViewModeEventHandler) Events [ModeChangingEvent];
-                               if (eh != null) eh (this, e);
+                               if (eh != null) {
+                                       eh (this, e);
+                                       return;
+                               }
                        }
+                       if (!IsBoundUsingDataSourceID)
+                               throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ModeChanging"));
                }
                
                protected virtual void OnItemUpdated (FormViewUpdatedEventArgs e)
@@ -262,8 +279,13 @@ namespace System.Web.UI.WebControls
                {
                        if (Events != null) {
                                FormViewUpdateEventHandler eh = (FormViewUpdateEventHandler) Events [ItemUpdatingEvent];
-                               if (eh != null) eh (this, e);
+                               if (eh != null) {
+                                       eh (this, e);
+                                       return;
+                               }
                        }
+                       if (!IsBoundUsingDataSourceID)
+                               throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemUpdating"));
                }
                
                
@@ -300,7 +322,7 @@ namespace System.Web.UI.WebControls
                [BrowsableAttribute (false)]
                public virtual FormViewRow BottomPagerRow {
                        get {
-                               EnsureDataBound ();
+                               EnsureChildControls ();
                                return bottomPagerRow;
                        }
                }
@@ -407,22 +429,42 @@ namespace System.Web.UI.WebControls
                        }
                }
                
+               IOrderedDictionary KeyTable {
+                       get {
+                               if (_keyTable == null) {
+                                       _keyTable = new OrderedDictionary (DataKeyNames.Length);
+                               }
+                               return _keyTable;
+                       }
+               }
+
                [BrowsableAttribute (false)]
                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public virtual DataKey DataKey {
                        get {
-                               EnsureDataBound ();
+                               if (key == null) {
+                                       key= new DataKey (KeyTable);
+                               }
                                return key;
                        }
                }
 
+               DataKey OldEditValues {
+                       get {
+                               if (oldEditValues == null) {
+                                       oldEditValues = new DataKey (new OrderedDictionary ());
+                               }
+                               return oldEditValues;
+                       }
+               }
+
                [DefaultValue (null)]
                [TemplateContainer (typeof(FormView), BindingDirection.TwoWay)]
                [PersistenceMode (PersistenceMode.InnerProperty)]
                [Browsable (false)]
                public virtual ITemplate EditItemTemplate {
                        get { return editItemTemplate; }
-                       set { editItemTemplate = value; RequireBinding (); }
+                       set { editItemTemplate = value; }
                }
 
                [WebCategoryAttribute ("Styles")]
@@ -463,7 +505,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate EmptyDataTemplate {
                        get { return emptyDataTemplate; }
-                       set { emptyDataTemplate = value; RequireBinding (); }
+                       set { emptyDataTemplate = value; }
                }
                
                [LocalizableAttribute (true)]
@@ -496,7 +538,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate FooterTemplate {
                        get { return footerTemplate; }
-                       set { footerTemplate = value; RequireBinding (); }
+                       set { footerTemplate = value; }
                }
 
                [LocalizableAttribute (true)]
@@ -574,7 +616,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate HeaderTemplate {
                        get { return headerTemplate; }
-                       set { headerTemplate = value; RequireBinding (); }
+                       set { headerTemplate = value; }
                }
 
                [LocalizableAttribute (true)]
@@ -611,7 +653,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate InsertItemTemplate {
                        get { return insertItemTemplate; }
-                       set { insertItemTemplate = value; RequireBinding (); }
+                       set { insertItemTemplate = value; }
                }
 
                [WebCategoryAttribute ("Styles")]
@@ -636,17 +678,18 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate ItemTemplate {
                        get { return itemTemplate; }
-                       set { itemTemplate = value; RequireBinding (); }
+                       set { itemTemplate = value; }
                }
                
                [BrowsableAttribute (false)]
                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public virtual int PageCount {
                        get {
-                               if (pageCount != 0) return pageCount;
-                               EnsureDataBound ();
                                return pageCount;
                        }
+                       private set {
+                               pageCount = value;
+                       }
                }
 
                [WebCategoryAttribute ("Paging")]
@@ -657,7 +700,9 @@ namespace System.Web.UI.WebControls
                                return pageIndex;
                        }
                        set {
-                               if (pageIndex == value)
+                               if (value < -1)
+                                       throw new ArgumentOutOfRangeException ("PageIndex must be non-negative");
+                               if (pageIndex == value || value == -1)
                                        return;
                                pageIndex = value;
                                RequireBinding ();
@@ -696,20 +741,19 @@ namespace System.Web.UI.WebControls
                
                
                [DefaultValue (null)]
-               /* DataControlPagerCell isnt specified in the docs */
-               //[TemplateContainer (typeof(DataControlPagerCell), BindingDirection.OneWay)]
+               [TemplateContainerAttribute (typeof (FormView))]
                [PersistenceMode (PersistenceMode.InnerProperty)]
                [Browsable (false)]
                public virtual ITemplate PagerTemplate {
                        get { return pagerTemplate; }
-                       set { pagerTemplate = value; RequireBinding (); }
+                       set { pagerTemplate = value; }
                }
                
                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                [BrowsableAttribute (false)]
                public virtual FormViewRow Row {
                        get {
-                               EnsureDataBound ();
+                               EnsureChildControls ();
                                return itemRow;
                        }
                }
@@ -740,7 +784,7 @@ namespace System.Web.UI.WebControls
                [BrowsableAttribute (false)]
                public virtual FormViewRow TopPagerRow {
                        get {
-                               EnsureDataBound ();
+                               EnsureChildControls ();
                                return topPagerRow;
                        }
                }
@@ -749,7 +793,6 @@ namespace System.Web.UI.WebControls
                [BrowsableAttribute (false)]
                public virtual object DataItem {
                        get {
-                               EnsureDataBound ();
                                return dataItem;
                        }
                }
@@ -781,20 +824,32 @@ namespace System.Web.UI.WebControls
                
                protected override DataSourceSelectArguments CreateDataSourceSelectArguments ()
                {
-                       return base.CreateDataSourceSelectArguments ();
+                       DataSourceSelectArguments arg = new DataSourceSelectArguments ();
+                       DataSourceView view = GetData ();
+                       if (AllowPaging && view.CanPage) {
+                               arg.StartRowIndex = PageIndex;
+                               if (view.CanRetrieveTotalRowCount) {
+                                       arg.RetrieveTotalRowCount = true;
+                                       arg.MaximumRows = 1;
+                               }
+                               else {
+                                       arg.MaximumRows = -1;
+                               }
+                       }
+                       return arg;
                }
                
                protected virtual FormViewRow CreateRow (int rowIndex, DataControlRowType rowType, DataControlRowState rowState)
                {
-                       FormViewRow row = new FormViewRow (rowIndex, rowType, rowState);
-                       OnItemCreated (EventArgs.Empty);
-                       return row;
+                       if (rowType == DataControlRowType.Pager)
+                               return new FormViewPagerRow (rowIndex, rowType, rowState);
+                       else
+                               return new FormViewRow (rowIndex, rowType, rowState);
                }
                
                void RequireBinding ()
                {
                        if (Initialized) {
-                               pageCount = -1;
                                RequiresDataBinding = true;
                        }
                }
@@ -804,10 +859,19 @@ namespace System.Web.UI.WebControls
                        return new ContainedTable (this);
                }
 
-               [MonoTODO]
                protected override void EnsureDataBound ()
                {
-                       base.EnsureDataBound ();
+                       if (CurrentMode == FormViewMode.Insert) {
+                               if (RequiresDataBinding) {
+                                       OnDataBinding (EventArgs.Empty);
+                                       RequiresDataBinding = false;
+                                       InternalPerformDataBinding (null);
+                                       MarkAsDataBound ();
+                                       OnDataBound (EventArgs.Empty);
+                               }
+                       }
+                       else
+                               base.EnsureDataBound ();
                }
        
                protected override Style CreateControlStyle ()
@@ -820,66 +884,82 @@ namespace System.Web.UI.WebControls
                protected override int CreateChildControls (IEnumerable data, bool dataBinding)
                {
                        PagedDataSource dataSource = new PagedDataSource ();
-                       dataSource.DataSource = data;
+                       dataSource.DataSource = CurrentMode != FormViewMode.Insert ? data : null;
                        dataSource.AllowPaging = AllowPaging;
                        dataSource.PageSize = 1;
                        dataSource.CurrentPageIndex = PageIndex;
 
-                       if (dataBinding) {
+                       if (dataBinding && CurrentMode != FormViewMode.Insert) {
                                DataSourceView view = GetData ();
                                if (view != null && view.CanPage) {
                                        dataSource.AllowServerPaging = true;
-                                       if (view.CanRetrieveTotalRowCount)
+                                       if (SelectArguments.RetrieveTotalRowCount)
                                                dataSource.VirtualCount = SelectArguments.TotalRowCount;
                                }
                        }
 
-                       pageCount = dataSource.DataSourceCount;
-                       bool showPager = AllowPaging && (pageCount > 1);
+                       PagerSettings pagerSettings = PagerSettings;
+                       bool showPager = AllowPaging && pagerSettings.Visible && (dataSource.PageCount > 1);
                        
                        Controls.Clear ();
                        table = CreateTable ();
                        Controls.Add (table);
+                       headerRow = null;
+                       footerRow = null;
+                       topPagerRow = null;
+                       bottomPagerRow = null;
 
                        // Gets the current data item
-                       
-                       IEnumerator e = dataSource.GetEnumerator (); 
-                       dataItem = null;
 
                        if (AllowPaging) {
-                               if (e.MoveNext ())
-                                       dataItem = e.Current;
+                               PageCount = dataSource.DataSourceCount;
+                               if (PageIndex >= PageCount && PageCount > 0) {
+                                       pageIndex = dataSource.CurrentPageIndex = PageCount - 1;
+                               }
+                               if (dataSource.DataSource != null) {
+                                       IEnumerator e = dataSource.GetEnumerator ();
+                                       if (e.MoveNext ())
+                                               dataItem = e.Current;
+                               }
                        }
-                       else
-                       for (int page = 0; e.MoveNext (); page++ )
-                               if (page == PageIndex)
-                                       dataItem = e.Current;
-                       
+                       else {
+                               int page = 0;
+                               object lastItem = null;
+                               if (dataSource.DataSource != null) {
+                                       IEnumerator e = dataSource.GetEnumerator ();
+                                       for (; e.MoveNext (); page++) {
+                                               lastItem = e.Current;
+                                               if (page == PageIndex)
+                                                       dataItem = e.Current;
+                                       }
+                               }
+                               PageCount = page;
+                               if (PageIndex >= PageCount && PageCount > 0) {
+                                       pageIndex = PageCount - 1;
+                                       dataItem = lastItem;
+                               }
+                       }
+
                        // Main table creation
-                       
-                       if (HeaderText.Length != 0 || headerTemplate != null) {
+                       bool emptyRow = PageCount == 0 && CurrentMode != FormViewMode.Insert;
+
+                       if (!emptyRow) {
                                headerRow = CreateRow (-1, DataControlRowType.Header, DataControlRowState.Normal);
                                InitializeRow (headerRow);
                                table.Rows.Add (headerRow);
                        }
-                       
-                       if (showPager && PagerSettings.Position == PagerPosition.Top || PagerSettings.Position == PagerPosition.TopAndBottom) {
+
+                       if (showPager && pagerSettings.Position == PagerPosition.Top || pagerSettings.Position == PagerPosition.TopAndBottom) {
                                topPagerRow = CreateRow (-1, DataControlRowType.Pager, DataControlRowState.Normal);
                                InitializePager (topPagerRow, dataSource);
                                table.Rows.Add (topPagerRow);
                        }
 
-                       if (pageCount > 0) {
+                       if (PageCount > 0) {
                                DataControlRowState rstate = GetRowState ();
                                itemRow = CreateRow (0, DataControlRowType.DataRow, rstate);
                                InitializeRow (itemRow);
                                table.Rows.Add (itemRow);
-                               
-                               if (!dataBinding) {
-                                       if (CurrentMode == FormViewMode.Edit)
-                                               oldEditValues = new DataKey (new OrderedDictionary ());
-                                       key = new DataKey (new OrderedDictionary (), DataKeyNames);
-                               }
                        } else {
                                switch (CurrentMode) {
                                case FormViewMode.Edit:
@@ -892,26 +972,28 @@ namespace System.Web.UI.WebControls
                                        itemRow = CreateRow (-1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);
                                        break;
                                }
-                               table.Rows.Add (itemRow);
                                InitializeRow (itemRow);
-                       }
-                               
-                       if (showPager && PagerSettings.Position == PagerPosition.Bottom || PagerSettings.Position == PagerPosition.TopAndBottom) {
-                               bottomPagerRow = CreateRow (0, DataControlRowType.Pager, DataControlRowState.Normal);
-                               InitializePager (bottomPagerRow, dataSource);
-                               table.Rows.Add (bottomPagerRow);
+                               table.Rows.Add (itemRow);
                        }
 
-                       if (FooterText.Length != 0 || footerTemplate != null) {
+                       if (!emptyRow) {
                                footerRow = CreateRow (-1, DataControlRowType.Footer, DataControlRowState.Normal);
                                InitializeRow (footerRow);
                                table.Rows.Add (footerRow);
                        }
                        
+                       if (showPager && pagerSettings.Position == PagerPosition.Bottom || pagerSettings.Position == PagerPosition.TopAndBottom) {
+                               bottomPagerRow = CreateRow (0, DataControlRowType.Pager, DataControlRowState.Normal);
+                               InitializePager (bottomPagerRow, dataSource);
+                               table.Rows.Add (bottomPagerRow);
+                       }
+
+                       OnItemCreated (EventArgs.Empty);
+                       
                        if (dataBinding)
                                DataBind (false);
-                       
-                       return dataSource.DataSourceCount;
+
+                       return PageCount;
                }
                
                DataControlRowState GetRowState ()
@@ -944,54 +1026,66 @@ namespace System.Web.UI.WebControls
                                if ((row.RowState & DataControlRowState.Edit) != 0) {
                                        if (editItemTemplate != null)
                                                editItemTemplate.InstantiateIn (cell);
+                                       else
+                                               row.Visible = false;
                                } else if ((row.RowState & DataControlRowState.Insert) != 0) {
                                        if (insertItemTemplate != null)
                                                insertItemTemplate.InstantiateIn (cell);
-                               } else if (itemTemplate != null)
+                                       else
+                                               row.Visible = false;
+                               }
+                               else if (itemTemplate != null)
                                        itemTemplate.InstantiateIn (cell);
+                               else
+                                       row.Visible = false;
                        }
                        else if (row.RowType == DataControlRowType.EmptyDataRow)
                        {
                                if (emptyDataTemplate != null)
                                        emptyDataTemplate.InstantiateIn (cell);
-                               else
+                               else if (!String.IsNullOrEmpty (EmptyDataText))
                                        cell.Text = EmptyDataText;
+                               else
+                                       row.Visible = false;
                        }
                        else if (row.RowType == DataControlRowType.Footer)
                        {
                                if (footerTemplate != null)
                                        footerTemplate.InstantiateIn (cell);
-                               else
+                               else if (!String.IsNullOrEmpty (FooterText))
                                        cell.Text = FooterText;
+                               else
+                                       row.Visible = false;
                        }
                        else if (row.RowType == DataControlRowType.Header)
                        {
                                if (headerTemplate != null)
                                        headerTemplate.InstantiateIn (cell);
-                               else
+                               else if (!String.IsNullOrEmpty (HeaderText))
                                        cell.Text = HeaderText;
+                               else
+                                       row.Visible = false;
                        }
                        cell.ColumnSpan = 2;
                        row.Cells.Add (cell);
                }
                
-               IOrderedDictionary CreateRowDataKey (object dataItem)
+               void FillRowDataKey (object dataItem)
                {
+                       KeyTable.Clear ();
+
                        if (cachedKeyProperties == null) {
                                PropertyDescriptorCollection props = TypeDescriptor.GetProperties (dataItem);
                                cachedKeyProperties = new PropertyDescriptor [DataKeyNames.Length];
                                for (int n=0; n<DataKeyNames.Length; n++) { 
-                                       PropertyDescriptor p = props [DataKeyNames[n]];
+                                       PropertyDescriptor p = props.Find (DataKeyNames [n], true);
                                        if (p == null)
-                                               new InvalidOperationException ("Property '" + DataKeyNames[n] + "' not found in object of type " + dataItem.GetType());
+                                               throw new InvalidOperationException ("Property '" + DataKeyNames[n] + "' not found in object of type " + dataItem.GetType());
                                        cachedKeyProperties [n] = p;
                                }
                        }
-                       
-                       OrderedDictionary dic = new OrderedDictionary ();
                        foreach (PropertyDescriptor p in cachedKeyProperties)
-                               dic [p.Name] = p.GetValue (dataItem);
-                       return dic;
+                               KeyTable [p.Name] = p.GetValue (dataItem);
                }
                
                IOrderedDictionary GetRowValues (bool includePrimaryKey)
@@ -1018,6 +1112,7 @@ namespace System.Web.UI.WebControls
                        
                        if (bt != null) {
                                IOrderedDictionary values = bt.ExtractValues (Row.Cells [0]);
+                               if (values != null)
                                foreach (DictionaryEntry e in values) {
                                        if (includeKeys || Array.IndexOf (DataKeyNames, e.Key) == -1)
                                                fieldValues [e.Key] = e.Value;
@@ -1033,29 +1128,14 @@ namespace System.Web.UI.WebControls
                
                public sealed override void DataBind ()
                {
-                       if (CurrentMode == FormViewMode.Insert) {
-                               RequiresDataBinding = false;
-                               PerformDataBinding (new object [] { null });
-                               return;
-                       }
-                       
-                       DataSourceView view = GetData ();
-                       if (AllowPaging && view.CanPage) {
-                               SelectArguments.StartRowIndex = PageIndex;
-                               SelectArguments.MaximumRows = 1;
-                               if (view.CanRetrieveTotalRowCount)
-                                       SelectArguments.RetrieveTotalRowCount = true;
-                       }
-
                        cachedKeyProperties = null;
                        base.DataBind ();
                        
                        if (pageCount > 0) {
                                if (CurrentMode == FormViewMode.Edit)
                                        oldEditValues = new DataKey (GetRowValues (true));
-                               else
-                                       oldEditValues = new DataKey (new OrderedDictionary ());
-                               key = new DataKey (CreateRowDataKey (dataItem), DataKeyNames);
+                               FillRowDataKey (dataItem);
+                               key = new DataKey (KeyTable);
                        }
                }
                
@@ -1114,13 +1194,25 @@ namespace System.Web.UI.WebControls
                {
                        FormViewCommandEventArgs args = e as FormViewCommandEventArgs;
                        if (args != null) {
-                               OnItemCommand (args);
-                               ProcessEvent (args.CommandName, args.CommandArgument as string);
+                               bool causesValidation = false;
+                               IButtonControl button = args.CommandSource as IButtonControl;
+                               if (button != null && button.CausesValidation) {
+                                       Page.Validate (button.ValidationGroup);
+                                       causesValidation = true;
+                               }
+                               ProcessCommand (args, causesValidation);
+                               return true;
                        }
                        return base.OnBubbleEvent (source, e);
                }
+
+               void ProcessCommand (FormViewCommandEventArgs args, bool causesValidation)
+               {
+                       OnItemCommand (args);
+                       ProcessEvent (args.CommandName, args.CommandArgument as string, causesValidation);
+               }
                
-                void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
+               void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
                {
                        RaisePostBackEvent (eventArgument);
                }
@@ -1128,13 +1220,15 @@ namespace System.Web.UI.WebControls
                protected virtual void RaisePostBackEvent (string eventArgument)
                {
                        int i = eventArgument.IndexOf ('$');
+                       CommandEventArgs arg;
                        if (i != -1)
-                               ProcessEvent (eventArgument.Substring (0, i), eventArgument.Substring (i + 1));
+                               arg = new CommandEventArgs (eventArgument.Substring (0, i), eventArgument.Substring (i + 1));
                        else
-                               ProcessEvent (eventArgument, null);
+                               arg = new CommandEventArgs (eventArgument, null);
+                       ProcessCommand (new FormViewCommandEventArgs (this, arg), false);
                }
-               
-               void ProcessEvent (string eventName, string param)
+
+               void ProcessEvent (string eventName, string param, bool causesValidation)
                {
                        switch (eventName)
                        {
@@ -1181,15 +1275,15 @@ namespace System.Web.UI.WebControls
                                break;
                                        
                        case DataControlCommands.EditCommandName:
-                               ChangeMode (FormViewMode.Edit);
+                               ProcessChangeMode (FormViewMode.Edit, false);
                                break;
                                        
                        case DataControlCommands.NewCommandName:
-                               ChangeMode (FormViewMode.Insert);
+                               ProcessChangeMode (FormViewMode.Insert, false);
                                break;
                                        
                        case DataControlCommands.UpdateCommandName:
-                               UpdateItem (param, true);
+                               UpdateItem (param, causesValidation);
                                break;
                                        
                        case DataControlCommands.CancelCommandName:
@@ -1201,43 +1295,51 @@ namespace System.Web.UI.WebControls
                                break;
                                        
                        case DataControlCommands.InsertCommandName:
-                               InsertItem (true);
+                               InsertItem (causesValidation);
                                break;
                        }
                }
                
-               void ShowPage (int newIndex)
+               void ShowPage (int index)
                {
-                       FormViewPageEventArgs args = new FormViewPageEventArgs (newIndex);
+                       FormViewPageEventArgs args = new FormViewPageEventArgs (index);
                        OnPageIndexChanging (args);
-                       if (!args.Cancel) {
-                               newIndex = args.NewPageIndex;
-                               if (newIndex < 0 || newIndex >= PageCount)
-                                       return;
-                               EndRowEdit (false);
-                               PageIndex = newIndex;
-                               OnPageIndexChanged (EventArgs.Empty);
-                       }
+
+                       if (args.Cancel || !IsBoundUsingDataSourceID)
+                               return;
+
+                       int newIndex = args.NewPageIndex;
+                       if (newIndex < 0 || newIndex >= PageCount)
+                               return;
+                       EndRowEdit (false, false);
+                       PageIndex = newIndex;
+                       OnPageIndexChanged (EventArgs.Empty);
                }
                
                public void ChangeMode (FormViewMode newMode)
                {
-                       FormViewModeEventArgs args = new FormViewModeEventArgs (newMode, false);
+                       if (CurrentMode == newMode)
+                               return;
+                       CurrentMode = newMode;
+                       RequireBinding ();
+               }
+
+               void ProcessChangeMode (FormViewMode newMode, bool cancelingEdit)
+               {
+                       FormViewModeEventArgs args = new FormViewModeEventArgs (newMode, cancelingEdit);
                        OnModeChanging (args);
-                       if (!args.Cancel) {
-                               CurrentMode = args.NewMode;
-                               OnModeChanged (EventArgs.Empty);
-                               RequireBinding ();
-                       }
+
+                       if (args.Cancel || !IsBoundUsingDataSourceID)
+                               return;
+
+                       ChangeMode (args.NewMode);
+
+                       OnModeChanged (EventArgs.Empty);
                }
                
                void CancelEdit ()
                {
-                       FormViewModeEventArgs args = new FormViewModeEventArgs (FormViewMode.ReadOnly, true);
-                       OnModeChanging (args);
-                       if (!args.Cancel) {
-                               EndRowEdit ();
-                       }
+                       EndRowEdit (true, true);
                }
 
                public virtual void UpdateItem (bool causesValidation)
@@ -1247,26 +1349,25 @@ namespace System.Web.UI.WebControls
                
                void UpdateItem (string param, bool causesValidation)
                {
-                       if (causesValidation)
-                               Page.Validate ();
-                       
-                       if (CurrentMode != FormViewMode.Edit) throw new NotSupportedException ();
+                       if (causesValidation && Page != null && !Page.IsValid)
+                               return;
                        
-                       currentEditOldValues = oldEditValues.Values;
+                       if (currentMode != FormViewMode.Edit) throw new HttpException ("Must be in Edit mode");
+
+                       currentEditOldValues = OldEditValues.Values;
                        currentEditRowKeys = DataKey.Values;
                        currentEditNewValues = GetRowValues (false);
                        
                        FormViewUpdateEventArgs args = new FormViewUpdateEventArgs (param, currentEditRowKeys, currentEditOldValues, currentEditNewValues);
                        OnItemUpdating (args);
-                       if (!args.Cancel) {
-                               DataSourceView view = GetData ();
-                               if (view == null)
-                                       throw new HttpException ("The DataSourceView associated to data bound control was null");
-                               if (view.CanUpdate)
-                                       view.Update (currentEditRowKeys, currentEditNewValues, currentEditOldValues, new DataSourceViewOperationCallback (UpdateCallback));
-                       }
-                       else
-                               EndRowEdit ();
+
+                       if (args.Cancel || !IsBoundUsingDataSourceID)
+                               return;
+                       
+                       DataSourceView view = GetData ();
+                       if (view == null)
+                               throw new HttpException ("The DataSourceView associated to data bound control was null");
+                       view.Update (currentEditRowKeys, currentEditNewValues, currentEditOldValues, new DataSourceViewOperationCallback (UpdateCallback));
                }
 
                bool UpdateCallback (int recordsAffected, Exception exception)
@@ -1275,7 +1376,7 @@ namespace System.Web.UI.WebControls
                        OnItemUpdated (dargs);
 
                        if (!dargs.KeepInEditMode)                              
-                               EndRowEdit ();
+                               EndRowEdit (true, false);
 
                        return dargs.ExceptionHandled;
                }
@@ -1287,23 +1388,22 @@ namespace System.Web.UI.WebControls
                
                void InsertItem (string param, bool causesValidation)
                {
-                       if (causesValidation)
-                               Page.Validate ();
+                       if (causesValidation && Page != null && !Page.IsValid)
+                               return;
                        
-                       if (CurrentMode != FormViewMode.Insert) throw new NotSupportedException ();
+                       if (currentMode != FormViewMode.Insert) throw new HttpException ("Must be in Insert mode");
                        
                        currentEditNewValues = GetRowValues (true);
                        FormViewInsertEventArgs args = new FormViewInsertEventArgs (param, currentEditNewValues);
                        OnItemInserting (args);
-                       if (!args.Cancel) {
-                               DataSourceView view = GetData ();
-                               if (view == null)
-                                       throw new HttpException ("The DataSourceView associated to data bound control was null");
-                               if (view.CanInsert)
-                                       view.Insert (currentEditNewValues, new DataSourceViewOperationCallback (InsertCallback));
-                       }
-                       else
-                               EndRowEdit ();
+
+                       if (args.Cancel || !IsBoundUsingDataSourceID)
+                               return;
+
+                       DataSourceView view = GetData ();
+                       if (view == null)
+                               throw new HttpException ("The DataSourceView associated to data bound control was null");
+                       view.Insert (currentEditNewValues, new DataSourceViewOperationCallback (InsertCallback));
                }
                
                bool InsertCallback (int recordsAffected, Exception exception)
@@ -1312,7 +1412,7 @@ namespace System.Web.UI.WebControls
                        OnItemInserted (dargs);
 
                        if (!dargs.KeepInInsertMode)                            
-                               EndRowEdit ();
+                               EndRowEdit (true, false);
 
                        return dargs.ExceptionHandled;
                }
@@ -1325,21 +1425,22 @@ namespace System.Web.UI.WebControls
                        FormViewDeleteEventArgs args = new FormViewDeleteEventArgs (PageIndex, currentEditRowKeys, currentEditNewValues);
                        OnItemDeleting (args);
 
-                       if (!args.Cancel) {
-                               if (PageIndex == PageCount - 1)
-                                       PageIndex --;
-                                       
-                               RequireBinding ();
-                                       
-                               DataSourceView view = GetData ();
-                               if (view != null && view.CanDelete)
-                                       view.Delete (currentEditRowKeys, currentEditNewValues, new DataSourceViewOperationCallback (DeleteCallback));
-                               else {
-                                       FormViewDeletedEventArgs dargs = new FormViewDeletedEventArgs (0, null, currentEditRowKeys, currentEditNewValues);
-                                       OnItemDeleted (dargs);
-                               }
+                       if (args.Cancel || !IsBoundUsingDataSourceID)
+                               return;
+
+                       if (PageIndex > 0 && PageIndex == PageCount - 1)
+                               PageIndex--;
+                               
+                       RequireBinding ();
+                               
+                       DataSourceView view = GetData ();
+                       if (view != null)
+                               view.Delete (currentEditRowKeys, currentEditNewValues, new DataSourceViewOperationCallback (DeleteCallback));
+                       else {
+                               FormViewDeletedEventArgs dargs = new FormViewDeletedEventArgs (0, null, currentEditRowKeys, currentEditNewValues);
+                               OnItemDeleted (dargs);
                        }
-               }
+               }       
 
                bool DeleteCallback (int recordsAffected, Exception exception)
                {
@@ -1348,15 +1449,10 @@ namespace System.Web.UI.WebControls
                        return dargs.ExceptionHandled;
                }
                
-               void EndRowEdit ()
-               {
-                       EndRowEdit (true);
-               }
-
-               void EndRowEdit (bool switchToDefaultMode) 
+               void EndRowEdit (bool switchToDefaultMode, bool cancelingEdit) 
                {
                        if (switchToDefaultMode)
-                               ChangeMode (DefaultMode);
+                               ProcessChangeMode (DefaultMode, cancelingEdit);
                        oldEditValues = new DataKey (new OrderedDictionary ());
                        currentEditRowKeys = null;
                        currentEditOldValues = null;
@@ -1374,13 +1470,24 @@ namespace System.Web.UI.WebControls
                        CurrentMode = (FormViewMode) state[3];
                        defaultMode = (FormViewMode) state[4];
                        dataKeyNames = (string[]) state[5];
+                       if (state [6] != null)
+                               ((IStateManager) DataKey).LoadViewState (state [6]);
+                       if (state [7] != null)
+                               ((IStateManager) OldEditValues).LoadViewState (state [7]);
                }
                
                protected internal override object SaveControlState ()
                {
                        object bstate = base.SaveControlState ();
-                       return new object[] {
-                               bstate, pageIndex, pageCount, CurrentMode, defaultMode, dataKeyNames
+                       return new object [] {
+                               bstate, 
+                               pageIndex, 
+                               pageCount, 
+                               CurrentMode, 
+                               defaultMode, 
+                               dataKeyNames,
+                               (key == null ? null : ((IStateManager)key).SaveViewState()),
+                               (oldEditValues == null ? null : ((IStateManager) oldEditValues).SaveViewState ())
                        };
                }
                
@@ -1395,23 +1502,20 @@ namespace System.Web.UI.WebControls
                        if (editRowStyle != null) ((IStateManager)editRowStyle).TrackViewState();
                        if (insertRowStyle != null) ((IStateManager)insertRowStyle).TrackViewState();
                        if (emptyDataRowStyle != null) ((IStateManager)emptyDataRowStyle).TrackViewState();
-                       if (key != null) ((IStateManager)key).TrackViewState();
                }
 
                protected override object SaveViewState()
                {
-                       object[] states = new object [14];
+                       object[] states = new object [10];
                        states[0] = base.SaveViewState();
-                       states[2] = (pagerSettings == null ? null : ((IStateManager)pagerSettings).SaveViewState());
-                       states[4] = (footerStyle == null ? null : ((IStateManager)footerStyle).SaveViewState());
-                       states[5] = (headerStyle == null ? null : ((IStateManager)headerStyle).SaveViewState());
-                       states[6] = (pagerStyle == null ? null : ((IStateManager)pagerStyle).SaveViewState());
-                       states[7] = (rowStyle == null ? null : ((IStateManager)rowStyle).SaveViewState());
-                       states[8] = (insertRowStyle == null ? null : ((IStateManager)insertRowStyle).SaveViewState());
-                       states[9] = (editRowStyle == null ? null : ((IStateManager)editRowStyle).SaveViewState());
-                       states[10] = (emptyDataRowStyle == null ? null : ((IStateManager)emptyDataRowStyle).SaveViewState());
-                       states[11] = (key == null ? null : ((IStateManager)key).SaveViewState());
-                       states[12] = (oldEditValues == null ? null : ((IStateManager)oldEditValues).SaveViewState());
+                       states[1] = (pagerSettings == null ? null : ((IStateManager)pagerSettings).SaveViewState());
+                       states[2] = (footerStyle == null ? null : ((IStateManager)footerStyle).SaveViewState());
+                       states[3] = (headerStyle == null ? null : ((IStateManager)headerStyle).SaveViewState());
+                       states[4] = (pagerStyle == null ? null : ((IStateManager)pagerStyle).SaveViewState());
+                       states[5] = (rowStyle == null ? null : ((IStateManager)rowStyle).SaveViewState());
+                       states[6] = (insertRowStyle == null ? null : ((IStateManager)insertRowStyle).SaveViewState());
+                       states[7] = (editRowStyle == null ? null : ((IStateManager)editRowStyle).SaveViewState());
+                       states[8] = (emptyDataRowStyle == null ? null : ((IStateManager)emptyDataRowStyle).SaveViewState());
                        
                        for (int i = states.Length - 1; i >= 0; i--) {
                                if (states [i] != null)
@@ -1431,18 +1535,15 @@ namespace System.Web.UI.WebControls
                        object [] states = (object []) savedState;
                        
                        base.LoadViewState (states[0]);
-                       EnsureChildControls ();
                        
-                       if (states[2] != null) ((IStateManager)PagerSettings).LoadViewState (states[2]);
-                       if (states[4] != null) ((IStateManager)FooterStyle).LoadViewState (states[4]);
-                       if (states[5] != null) ((IStateManager)HeaderStyle).LoadViewState (states[5]);
-                       if (states[6] != null) ((IStateManager)PagerStyle).LoadViewState (states[6]);
-                       if (states[7] != null) ((IStateManager)RowStyle).LoadViewState (states[7]);
-                       if (states[8] != null) ((IStateManager)InsertRowStyle).LoadViewState (states[8]);
-                       if (states[9] != null) ((IStateManager)EditRowStyle).LoadViewState (states[9]);
-                       if (states[10] != null) ((IStateManager)EmptyDataRowStyle).LoadViewState (states[10]);
-                       if (states[11] != null && DataKey != null) ((IStateManager)DataKey).LoadViewState (states[11]);
-                       if (states[12] != null && oldEditValues != null) ((IStateManager)oldEditValues).LoadViewState (states[12]);
+                       if (states[1] != null) ((IStateManager)PagerSettings).LoadViewState (states[1]);
+                       if (states[2] != null) ((IStateManager)FooterStyle).LoadViewState (states[2]);
+                       if (states[3] != null) ((IStateManager)HeaderStyle).LoadViewState (states[3]);
+                       if (states[4] != null) ((IStateManager)PagerStyle).LoadViewState (states[4]);
+                       if (states[5] != null) ((IStateManager)RowStyle).LoadViewState (states[5]);
+                       if (states[6] != null) ((IStateManager)InsertRowStyle).LoadViewState (states[6]);
+                       if (states[7] != null) ((IStateManager)EditRowStyle).LoadViewState (states[7]);
+                       if (states[8] != null) ((IStateManager)EmptyDataRowStyle).LoadViewState (states[8]);
                }
                
                protected internal override void Render (HtmlTextWriter writer)
@@ -1457,8 +1558,17 @@ namespace System.Web.UI.WebControls
 
                PostBackOptions IPostBackContainer.GetPostBackOptions (IButtonControl control)
                {
-                       Control ctrl = control as Control;
-                       return new PostBackOptions(ctrl);
+                       if (control == null)
+                               throw new ArgumentNullException ("control");
+
+                       if (control.CausesValidation)
+                               throw new InvalidOperationException ("A button that causes validation in FormView '" + ID + "' is attempting to use the container GridView as the post back target.  The button should either turn off validation or use itself as the post back container.");
+
+                       PostBackOptions options = new PostBackOptions (this);
+                       options.Argument = control.CommandName + "$" + control.CommandArgument;
+                       options.RequiresJavaScriptProtocol = true;
+
+                       return options;
                }
 
        }