New tests.
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / GridView.cs
index ed801e061068432f77387fb007352118aa6b3790..26ace72c5ce04e6ab91bba0de75cd5e2295ab890 100644 (file)
@@ -46,7 +46,7 @@ namespace System.Web.UI.WebControls
        [DefaultEventAttribute ("SelectedIndexChanged")]
        [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
-       public class GridView: CompositeDataBoundControl, ICallbackEventHandler, ICallbackContainer, IPostBackEventHandler, IPostBackContainer
+       public class GridView: CompositeDataBoundControl, ICallbackEventHandler, ICallbackContainer, IPostBackEventHandler, IPostBackContainer, IPersistedSelector
        {
                Table table;
                GridViewRowCollection rows;
@@ -80,22 +80,23 @@ namespace System.Web.UI.WebControls
                AutoGeneratedFieldProperties[] autoFieldProperties;
                string [] dataKeyNames = null;
                readonly string[] emptyKeys = new string[0];
-               
-               private static readonly object PageIndexChangedEvent = new object();
-               private static readonly object PageIndexChangingEvent = new object();
-               private static readonly object RowCancelingEditEvent = new object();
-               private static readonly object RowCommandEvent = new object();
-               private static readonly object RowCreatedEvent = new object();
-               private static readonly object RowDataBoundEvent = new object();
-               private static readonly object RowDeletedEvent = new object();
-               private static readonly object RowDeletingEvent = new object();
-               private static readonly object RowEditingEvent = new object();
-               private static readonly object RowUpdatedEvent = new object();
-               private static readonly object RowUpdatingEvent = new object();
-               private static readonly object SelectedIndexChangedEvent = new object();
-               private static readonly object SelectedIndexChangingEvent = new object();
-               private static readonly object SortedEvent = new object();
-               private static readonly object SortingEvent = new object();
+               IEnumerator _dataEnumerator;
+               
+               static readonly object PageIndexChangedEvent = new object();
+               static readonly object PageIndexChangingEvent = new object();
+               static readonly object RowCancelingEditEvent = new object();
+               static readonly object RowCommandEvent = new object();
+               static readonly object RowCreatedEvent = new object();
+               static readonly object RowDataBoundEvent = new object();
+               static readonly object RowDeletedEvent = new object();
+               static readonly object RowDeletingEvent = new object();
+               static readonly object RowEditingEvent = new object();
+               static readonly object RowUpdatedEvent = new object();
+               static readonly object RowUpdatingEvent = new object();
+               static readonly object SelectedIndexChangedEvent = new object();
+               static readonly object SelectedIndexChangingEvent = new object();
+               static readonly object SortedEvent = new object();
+               static readonly object SortingEvent = new object();
                
                // Control state
                int pageIndex;
@@ -343,6 +344,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == AllowPaging)
+                                       return;
                                ViewState ["AllowPaging"] = value;
                                RequireBinding ();
                        }
@@ -357,6 +360,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == AllowSorting)
+                                       return;
                                ViewState ["AllowSorting"] = value;
                                RequireBinding ();
                        }
@@ -386,6 +391,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == AutoGenerateEditButton)
+                                       return;
                                ViewState ["AutoGenerateEditButton"] = value;
                                RequireBinding ();
                        }
@@ -400,6 +407,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == AutoGenerateDeleteButton)
+                                       return;
                                ViewState ["AutoGenerateDeleteButton"] = value;
                                RequireBinding ();
                        }
@@ -414,6 +423,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == AutoGenerateSelectButton)
+                                       return;
                                ViewState ["AutoGenerateSelectButton"] = value;
                                RequireBinding ();
                        }
@@ -428,6 +439,8 @@ namespace System.Web.UI.WebControls
                                return true;
                        }
                        set {
+                               if (value == AutoGenerateColumns)
+                                       return;
                                ViewState ["AutoGenerateColumns"] = value;
                                RequireBinding ();
                        }
@@ -468,7 +481,6 @@ namespace System.Web.UI.WebControls
                        }
                        set {
                                ViewState ["Caption"] = value;
-                               RequireBinding ();
                        }
                }
                
@@ -483,7 +495,6 @@ namespace System.Web.UI.WebControls
                        }
                        set {
                                ViewState ["CaptionAlign"] = value;
-                               RequireBinding ();
                        }
                }
 
@@ -532,6 +543,12 @@ namespace System.Web.UI.WebControls
                        }
                }
 
+               [BrowsableAttribute(false)]
+               public IAutoFieldGenerator ColumnsGenerator {
+                       get;
+                       set;
+               }
+
                [DefaultValueAttribute (null)]
                [WebCategoryAttribute ("Data")]
                [TypeConverter (typeof(StringArrayConverter))]
@@ -630,7 +647,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate EmptyDataTemplate {
                        get { return emptyDataTemplate; }
-                       set { emptyDataTemplate = value; RequireBinding (); }
+                       set { emptyDataTemplate = value; }
                }
                
                [LocalizableAttribute (true)]
@@ -643,6 +660,8 @@ namespace System.Web.UI.WebControls
                                return string.Empty;
                        }
                        set {
+                               if (value == EmptyDataText)
+                                       return;
                                ViewState ["EmptyDataText"] = value;
                                RequireBinding ();
                        }
@@ -657,6 +676,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == EnableSortingAndPagingCallbacks)
+                                       return;
                                ViewState ["EnableSortingAndPagingCallbacks"] = value;
                                RequireBinding ();
                        }
@@ -799,6 +820,8 @@ namespace System.Web.UI.WebControls
                                return 10;
                        }
                        set {
+                               if (value == PageSize)
+                                       return;
                                ViewState ["PageSize"] = value;
                                RequireBinding ();
                        }
@@ -842,7 +865,7 @@ namespace System.Web.UI.WebControls
                [Browsable (false)]
                public virtual ITemplate PagerTemplate {
                        get { return pagerTemplate; }
-                       set { pagerTemplate = value; RequireBinding (); }
+                       set { pagerTemplate = value; }
                }
                
                [DefaultValueAttribute ("")]
@@ -855,6 +878,8 @@ namespace System.Web.UI.WebControls
                                return string.Empty;
                        }
                        set {
+                               if (value == RowHeaderColumn)
+                                       return;
                                ViewState ["RowHeaderColumn"] = value;
                                RequireBinding ();
                        }
@@ -890,8 +915,8 @@ namespace System.Web.UI.WebControls
                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public virtual DataKey SelectedDataKey {
                        get {
-                               if (keys == null)
-                                       throw new InvalidOperationException ("DataKeys");
+                               if (DataKeyNames.Length == 0)
+                                       throw new InvalidOperationException (String.Format ("Data keys must be specified on GridView '{0}' before the selected data keys can be retrieved.  Use the DataKeyNames property to specify data keys.", ID));
 
                                if (selectedIndex >= 0 && selectedIndex < DataKeys.Count) {
                                        return DataKeys [selectedIndex];
@@ -899,6 +924,18 @@ namespace System.Web.UI.WebControls
                                        return null;
                        }
                }
+
+               [MonoTODO]
+               [BrowsableAttribute(false)]
+               public virtual DataKey SelectedPersistedDataKey {
+                       get; set;
+               }
+
+               [MonoTODO]
+               DataKey IPersistedSelector.DataKey {
+                       get { return SelectedPersistedDataKey; }
+                       set { SelectedPersistedDataKey = value; }
+               }
                
                [BindableAttribute (true)]
                [DefaultValueAttribute (-1)]
@@ -907,13 +944,13 @@ namespace System.Web.UI.WebControls
                                return selectedIndex;
                        }
                        set {
-                               if (Rows != null && selectedIndex >= 0 && selectedIndex < Rows.Count) {
+                               if (rows != null && selectedIndex >= 0 && selectedIndex < Rows.Count) {
                                        int oldIndex = selectedIndex;
                                        selectedIndex = -1;
                                        Rows [oldIndex].RowState = GetRowState (oldIndex);
                                }
                                selectedIndex = value;
-                               if (Rows != null && selectedIndex >= 0 && selectedIndex < Rows.Count) {
+                               if (rows != null && selectedIndex >= 0 && selectedIndex < Rows.Count) {
                                        Rows [selectedIndex].RowState = GetRowState (selectedIndex);
                                }
                        }
@@ -964,6 +1001,8 @@ namespace System.Web.UI.WebControls
                                return false;
                        }
                        set {
+                               if (value == ShowFooter)
+                                       return;
                                ViewState ["ShowFooter"] = value;
                                RequireBinding ();
                        }
@@ -978,6 +1017,8 @@ namespace System.Web.UI.WebControls
                                return true;
                        }
                        set {
+                               if (value == ShowHeader)
+                                       return;
                                ViewState ["ShowHeader"] = value;
                                RequireBinding ();
                        }
@@ -1031,6 +1072,8 @@ namespace System.Web.UI.WebControls
                                return true;
                        }
                        set {
+                               if (value == UseAccessibleHeader)
+                                       return;
                                ViewState ["UseAccessibleHeader"] = value;
                                RequireBinding ();
                        }
@@ -1038,7 +1081,7 @@ namespace System.Web.UI.WebControls
        
                public virtual bool IsBindableType (Type type)
                {
-                       return type.IsPrimitive || type == typeof(string) || type == typeof(DateTime) || type == typeof(Guid);
+                       return type.IsPrimitive || type == typeof (string) || type == typeof (decimal) || type == typeof (DateTime) || type == typeof (Guid);
                }
                
                // MSDN: The CreateDataSourceSelectArguments method is a helper method called by 
@@ -1072,6 +1115,14 @@ namespace System.Web.UI.WebControls
                
                protected virtual ICollection CreateColumns (PagedDataSource dataSource, bool useDataSource)
                {
+                       bool autoGenerate = AutoGenerateColumns;
+
+                       if (autoGenerate) {
+                               IAutoFieldGenerator fieldGenerator = ColumnsGenerator;
+                               if (fieldGenerator != null)
+                                       return fieldGenerator.GenerateFields (this);
+                       }
+                       
                        ArrayList fields = new ArrayList ();
                        
                        if (AutoGenerateEditButton || AutoGenerateDeleteButton || AutoGenerateSelectButton) {
@@ -1084,7 +1135,7 @@ namespace System.Web.UI.WebControls
 
                        fields.AddRange (Columns);
                        
-                       if (AutoGenerateColumns) {
+                       if (autoGenerate) {
                                if (useDataSource)
                                        autoFieldProperties = CreateAutoFieldProperties (dataSource);
        
@@ -1126,8 +1177,10 @@ namespace System.Web.UI.WebControls
                                
                                if (prop_type == null || prop_type == typeof(object)) {
                                        IEnumerator en = source.GetEnumerator();
-                                       if (en.MoveNext())
+                                       if (en != null && en.MoveNext ()) {
                                                fitem = en.Current;
+                                               _dataEnumerator = en;
+                                       }
                                        if (fitem != null)
                                                prop_type = fitem.GetType();
                                }
@@ -1156,7 +1209,12 @@ namespace System.Web.UI.WebControls
                                                ((IStateManager)field).TrackViewState();
                                                field.Name = current.Name;
                                                field.DataField = current.Name;
-                                               field.IsReadOnly = current.IsReadOnly;
+                                               for (int i = 0; i < DataKeyNames.Length; i++) {
+                                                       if (string.Compare (DataKeyNames [i], current.Name, StringComparison.InvariantCultureIgnoreCase) == 0) {
+                                                               field.IsReadOnly = true;
+                                                               break;
+                                                       }
+                                               }
                                                field.Type = current.PropertyType;
                                                retVal.Add (field);
                                        }
@@ -1193,7 +1251,7 @@ namespace System.Web.UI.WebControls
                        Controls.Clear ();
                        table = null;
                        rows = null;
-                       
+
                        if (data == null) {
                                return 0;
                        }
@@ -1208,12 +1266,14 @@ namespace System.Web.UI.WebControls
                                if (AllowPaging) {
                                        dataSource.AllowPaging = true;
                                        dataSource.PageSize = PageSize;
-                                       dataSource.CurrentPageIndex = PageIndex;
                                        if (view.CanPage) {
                                                dataSource.AllowServerPaging = true;
                                                if (SelectArguments.RetrieveTotalRowCount)
                                                        dataSource.VirtualCount = SelectArguments.TotalRowCount;
                                        }
+                                       if (PageIndex >= dataSource.PageCount)
+                                               pageIndex = dataSource.PageCount - 1;
+                                       dataSource.CurrentPageIndex = PageIndex;
                                }
                                
                                PageCount = dataSource.PageCount;
@@ -1229,93 +1289,136 @@ namespace System.Web.UI.WebControls
                                }
                        }
 
-                       if (dataSource.DataSourceCount == 0)
-                               return 0;
+                       bool createPager = AllowPaging && (PageCount >= 1) && PagerSettings.Visible;
 
-                       bool showPager = AllowPaging && (PageCount > 1);
-                       
-                       table = CreateChildTable ();
-                       Controls.Add (table);
-                               
                        ArrayList list = new ArrayList ();
                        
                        // Creates the set of fields to show
-                       
+
+                       _dataEnumerator = null;
                        ICollection fieldCollection = CreateColumns (dataSource, dataBinding);
-                       DataControlField[] fields = new DataControlField [fieldCollection.Count];
+                       int fieldCount = fieldCollection.Count;
+                       DataControlField dcf;
+                       DataControlField[] fields = new DataControlField [fieldCount];
                        fieldCollection.CopyTo (fields, 0);
-
-                       foreach (DataControlField field in fields) {
-                               field.Initialize (AllowSorting, this);
+                       
+                       for (int i = 0; i < fieldCount; i++) {
+                               dcf = fields [i];
+                               dcf.Initialize (AllowSorting, this);
                                if (EnableSortingAndPagingCallbacks)
-                                       field.ValidateSupportsCallback ();
+                                       dcf.ValidateSupportsCallback ();
                        }
 
-                       // Main table creation
-                       
-                       if (showPager && PagerSettings.Position == PagerPosition.Top || PagerSettings.Position == PagerPosition.TopAndBottom) {
-                               topPagerRow = CreatePagerRow (fields.Length, dataSource);
-                               table.Rows.Add (topPagerRow);
-                               OnRowCreated (new GridViewRowEventArgs (topPagerRow));
+                       bool skip_first = false;
+                       IEnumerator enumerator;
+                       if (_dataEnumerator != null) {
+                               // replaced when creating bound columns
+                               enumerator = _dataEnumerator;
+                               skip_first = true;
                        }
-
-                       GridViewRow headerRow = CreateRow (0, 0, DataControlRowType.Header, DataControlRowState.Normal);
-                       table.Rows.Add (headerRow);
-                       InitializeRow (headerRow, fields);
-                       OnRowCreated (new GridViewRowEventArgs (headerRow));
-                       if (dataBinding) {
-                               headerRow.DataBind ();
-                               OnRowDataBound (new GridViewRowEventArgs (headerRow));
+                       else {
+                               enumerator = dataSource.GetEnumerator ();
                        }
-                       
-                       foreach (object obj in dataSource) {
+
+                       // Main table creation
+                       Table mainTable = ContainedTable;
+                       while (skip_first || enumerator.MoveNext ()) {
+                               skip_first = false;
+                               object obj = enumerator.Current;
+                               
+                               if (list.Count == 0) {
+                                       if (createPager && (PagerSettings.Position == PagerPosition.Top || PagerSettings.Position == PagerPosition.TopAndBottom)) {
+                                               topPagerRow = CreatePagerRow (fieldCount, dataSource);
+                                               OnRowCreated (new GridViewRowEventArgs (topPagerRow));
+                                               mainTable.Rows.Add (topPagerRow);
+                                               if (dataBinding) {
+                                                       topPagerRow.DataBind ();
+                                                       OnRowDataBound (new GridViewRowEventArgs (topPagerRow));
+                                               }
+                                               if (PageCount == 1)
+                                                       topPagerRow.Visible = false;
+                                       }
+
+                                       GridViewRow headerRow = CreateRow (-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
+                                       InitializeRow (headerRow, fields);
+                                       OnRowCreated (new GridViewRowEventArgs (headerRow));
+                                       mainTable.Rows.Add (headerRow);
+                                       if (dataBinding) {
+                                               headerRow.DataBind ();
+                                               OnRowDataBound (new GridViewRowEventArgs (headerRow));
+                                       }
+                               }
+                               
                                DataControlRowState rstate = GetRowState (list.Count);
                                GridViewRow row = CreateRow (list.Count, list.Count, DataControlRowType.DataRow, rstate);
                                row.DataItem = obj;
                                list.Add (row);
-                               table.Rows.Add (row);
                                InitializeRow (row, fields);
                                OnRowCreated (new GridViewRowEventArgs (row));
+                               mainTable.Rows.Add (row);
                                if (dataBinding) {
-                                       row.DataBind ();
-                                       OnRowDataBound (new GridViewRowEventArgs (row));
+                                       row.DataBind ();                                        
                                        if (EditIndex == row.RowIndex)
-                                               oldEditValues = new DataKey (GetRowValues (row, false, true));
+                                               oldEditValues = new DataKey (GetRowValues (row, true, true));
                                        DataKeyArrayList.Add (new DataKey (CreateRowDataKey (row), DataKeyNames));
+                                       OnRowDataBound (new GridViewRowEventArgs (row));
                                } 
-
-                               if (list.Count >= PageSize)
-                                       break;
                        }
 
                        if (list.Count == 0) {
-                               GridViewRow emptyRow = CreateEmptyrRow (fields.Length);
-                               table.Rows.Add (emptyRow);
-                               OnRowCreated (new GridViewRowEventArgs (emptyRow));
-                               if (dataBinding) {
-                                       emptyRow.DataBind ();
-                                       OnRowDataBound (new GridViewRowEventArgs (emptyRow));
+                               GridViewRow emptyRow = CreateEmptyrRow (fieldCount);
+                               if (emptyRow != null) {
+                                       OnRowCreated (new GridViewRowEventArgs (emptyRow));
+                                       mainTable.Rows.Add (emptyRow);
+                                       if (dataBinding) {
+                                               emptyRow.DataBind ();
+                                               OnRowDataBound (new GridViewRowEventArgs (emptyRow));
+                                       }
                                }
+                               return 0;
                        }
+                       else {
+                               GridViewRow footerRow = CreateRow (-1, -1, DataControlRowType.Footer, DataControlRowState.Normal);
+                               InitializeRow (footerRow, fields);
+                               OnRowCreated (new GridViewRowEventArgs (footerRow));
+                               mainTable.Rows.Add (footerRow);
+                               if (dataBinding) {
+                                       footerRow.DataBind ();
+                                       OnRowDataBound (new GridViewRowEventArgs (footerRow));
+                               }
 
-                       GridViewRow footerRow = CreateRow (0, 0, DataControlRowType.Footer, DataControlRowState.Normal);
-                       table.Rows.Add (footerRow);
-                       InitializeRow (footerRow, fields);
-                       OnRowCreated (new GridViewRowEventArgs (footerRow));
-                       if (dataBinding) {
-                               footerRow.DataBind ();
-                               OnRowDataBound (new GridViewRowEventArgs (footerRow));
-                       }
-
-                       if (showPager && PagerSettings.Position == PagerPosition.Bottom || PagerSettings.Position == PagerPosition.TopAndBottom) {
-                               bottomPagerRow = CreatePagerRow (fields.Length, dataSource);
-                               table.Rows.Add (bottomPagerRow);
-                               OnRowCreated (new GridViewRowEventArgs (bottomPagerRow));
+                               if (createPager && (PagerSettings.Position == PagerPosition.Bottom || PagerSettings.Position == PagerPosition.TopAndBottom)) {
+                                       bottomPagerRow = CreatePagerRow (fieldCount, dataSource);
+                                       OnRowCreated (new GridViewRowEventArgs (bottomPagerRow));
+                                       mainTable.Rows.Add (bottomPagerRow);
+                                       if (dataBinding) {
+                                               bottomPagerRow.DataBind ();
+                                               OnRowDataBound (new GridViewRowEventArgs (bottomPagerRow));
+                                       }
+                                       if (PageCount == 1)
+                                               bottomPagerRow.Visible = false;
+                               }
                        }
 
                        rows = new GridViewRowCollection (list);
 
-                       return dataSource.DataSourceCount;
+                       if (!dataBinding)
+                               return -1;
+
+                       if (AllowPaging)
+                               return dataSource.DataSourceCount;
+                       else
+                               return list.Count;
+               }
+
+               Table ContainedTable  {
+                       get {
+                               if (table == null) {
+                                       table = CreateChildTable ();
+                                       Controls.Add (table);
+                               }
+                               return table;
+                       }
                }
 
                protected override Style CreateControlStyle ()
@@ -1357,6 +1460,9 @@ namespace System.Web.UI.WebControls
                
                GridViewRow CreateEmptyrRow (int fieldCount)
                {
+                       if (emptyDataTemplate == null && String.IsNullOrEmpty (EmptyDataText))
+                               return null;
+
                        GridViewRow row = CreateRow (-1, -1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);
                        TableCell cell = new TableCell ();
                        cell.ColumnSpan = fieldCount;
@@ -1390,6 +1496,7 @@ namespace System.Web.UI.WebControls
                        
                        for (int n=0; n<fields.Length; n++) {
                                DataControlField field = fields [n];
+                               
                                DataControlFieldCell cell;
                                if (((field is BoundField) && ((BoundField)field).DataField == RowHeaderColumn) || accessibleHeader)
                                        cell = new DataControlFieldHeaderCell (field, accessibleHeader ? TableHeaderScope.Column : TableHeaderScope.Row);
@@ -1428,10 +1535,17 @@ namespace System.Web.UI.WebControls
                
                protected virtual void ExtractRowValues (IOrderedDictionary fieldValues, GridViewRow row, bool includeReadOnlyFields, bool includePrimaryKey)
                {
+                       DataControlField field;
                        foreach (TableCell cell in row.Cells) {
                                DataControlFieldCell c = cell as DataControlFieldCell;
-                               if (c != null)
-                                       c.ContainingField.ExtractValuesFromCell (fieldValues, c, row.RowState, includeReadOnlyFields);
+                               if (c == null)
+                                       continue;
+                               
+                               field = c.ContainingField;
+                               if (field != null && !field.Visible)
+                                       continue;
+                               
+                               c.ContainingField.ExtractValuesFromCell (fieldValues, c, row.RowState, includeReadOnlyFields);
                        }
                        if (!includePrimaryKey && DataKeyNames != null)
                                foreach (string key in DataKeyNames)
@@ -1454,6 +1568,14 @@ namespace System.Web.UI.WebControls
                        base.DataBind ();
 
                        keys = new DataKeyArray (DataKeyArrayList);
+                       
+                       GridViewRow row = HeaderRow;
+                       if (row != null)
+                               row.Visible = ShowHeader;
+
+                       row = FooterRow;
+                       if (row != null)
+                               row.Visible = ShowFooter;
                }
                
                protected internal override void PerformDataBinding (IEnumerable data)
@@ -1465,39 +1587,40 @@ namespace System.Web.UI.WebControls
                {
                        if (table == null)
                                return;
-                       
+
                        table.Caption = Caption;
                        table.CaptionAlign = CaptionAlign;
+                       table.CopyBaseAttributes (this);
                        
                        foreach (GridViewRow row in table.Rows) {
                                switch (row.RowType) {
                                case DataControlRowType.Header:
                                        if (headerStyle != null && !headerStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom(headerStyle);
+                                               row.ControlStyle.MergeWith(headerStyle);
                                        row.Visible = ShowHeader;
                                        break;
                                case DataControlRowType.Footer:
                                        if (footerStyle != null && !footerStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (footerStyle);
+                                               row.ControlStyle.MergeWith (footerStyle);
                                        row.Visible = ShowFooter;
                                        break;
                                case DataControlRowType.Pager:
                                        if (pagerStyle != null && !pagerStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (pagerStyle);
+                                               row.ControlStyle.MergeWith (pagerStyle);
                                        break;
                                case DataControlRowType.EmptyDataRow:
                                        if (emptyDataRowStyle != null && !emptyDataRowStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (emptyDataRowStyle);
+                                               row.ControlStyle.MergeWith (emptyDataRowStyle);
                                        break;
                                case DataControlRowType.DataRow:
-                                       if (rowStyle != null && !rowStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (rowStyle);
-                                       if ((row.RowState & DataControlRowState.Alternate) != 0 && alternatingRowStyle != null && !alternatingRowStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (alternatingRowStyle);
-                                       if ((row.RowState & DataControlRowState.Selected) != 0 && selectedRowStyle != null && !selectedRowStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (selectedRowStyle);
                                        if ((row.RowState & DataControlRowState.Edit) != 0 && editRowStyle != null && !editRowStyle.IsEmpty)
-                                               row.ControlStyle.CopyFrom (editRowStyle);
+                                               row.ControlStyle.MergeWith (editRowStyle);
+                                       if ((row.RowState & DataControlRowState.Selected) != 0 && selectedRowStyle != null && !selectedRowStyle.IsEmpty)
+                                               row.ControlStyle.MergeWith (selectedRowStyle);
+                                       if ((row.RowState & DataControlRowState.Alternate) != 0 && alternatingRowStyle != null && !alternatingRowStyle.IsEmpty)
+                                               row.ControlStyle.MergeWith (alternatingRowStyle);
+                                       if (rowStyle != null && !rowStyle.IsEmpty)
+                                               row.ControlStyle.MergeWith (rowStyle);
                                        break;
                                default:
                                        break;
@@ -1507,14 +1630,21 @@ namespace System.Web.UI.WebControls
                                        DataControlFieldCell fcell = cell as DataControlFieldCell;
                                        if (fcell != null) {
                                                DataControlField field = fcell.ContainingField;
+                                               if (field == null)
+                                                       continue;
+                                               if (!field.Visible) {
+                                                       cell.Visible = false;
+                                                       continue;
+                                               }
+                                               
                                                switch (row.RowType) {
                                                case DataControlRowType.Header:
                                                        if (field.HeaderStyleCreated && !field.HeaderStyle.IsEmpty)
-                                                               cell.ControlStyle.CopyFrom (field.HeaderStyle);
+                                                               cell.ControlStyle.MergeWith (field.HeaderStyle);
                                                        break;
                                                case DataControlRowType.Footer:
                                                        if (field.FooterStyleCreated && !field.FooterStyle.IsEmpty)
-                                                               cell.ControlStyle.CopyFrom (field.FooterStyle);
+                                                               cell.ControlStyle.MergeWith (field.FooterStyle);
                                                        break;
                                                default:
                                                        if (field.ControlStyleCreated && !field.ControlStyle.IsEmpty)
@@ -1524,7 +1654,7 @@ namespace System.Web.UI.WebControls
                                                                                wc.ControlStyle.MergeWith (field.ControlStyle);
                                                                }
                                                        if (field.ItemStyleCreated && !field.ItemStyle.IsEmpty)
-                                                               cell.ControlStyle.CopyFrom (field.ItemStyle);
+                                                               cell.ControlStyle.MergeWith (field.ItemStyle);
                                                        break;
                                                }
                                        }
@@ -1559,6 +1689,12 @@ namespace System.Web.UI.WebControls
                {
                        GridViewCommandEventArgs args = e as GridViewCommandEventArgs;
                        if (args != null) {
+                               bool causesValidation = false;
+                               IButtonControl button = args.CommandSource as IButtonControl;
+                               if (button != null && button.CausesValidation) {
+                                       Page.Validate (button.ValidationGroup);
+                                       causesValidation = true;
+                               }
                                OnRowCommand (args);
                                string param = args.CommandArgument as string;
                                if (param == null || param.Length == 0) {
@@ -1566,7 +1702,7 @@ namespace System.Web.UI.WebControls
                                        if (row != null)
                                                param = row.RowIndex.ToString();
                                }
-                               ProcessEvent (args.CommandName, param);
+                               ProcessEvent (args.CommandName, param, causesValidation);
                                return true;
                        }
                        return base.OnBubbleEvent (source, e);
@@ -1574,20 +1710,25 @@ namespace System.Web.UI.WebControls
                
                void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
                {
+                       ValidateEvent (UniqueID, eventArgument);
                        RaisePostBackEvent (eventArgument);
                }
 
                // This is prolly obsolete
                protected virtual void RaisePostBackEvent (string eventArgument)
                {
+                       GridViewCommandEventArgs args;
                        int i = eventArgument.IndexOf ('$');
                        if (i != -1)
-                               ProcessEvent (eventArgument.Substring (0, i), eventArgument.Substring (i + 1));
+                               args = new GridViewCommandEventArgs (this, new CommandEventArgs (eventArgument.Substring (0, i), eventArgument.Substring (i + 1)));
                        else
-                               ProcessEvent (eventArgument, null);
+                               args = new GridViewCommandEventArgs (this, new CommandEventArgs (eventArgument, null));
+
+                       OnRowCommand (args);
+                       ProcessEvent (args.CommandName, (string) args.CommandArgument, false);
                }
-               
-               void ProcessEvent (string eventName, string param)
+
+               void ProcessEvent (string eventName, string param, bool causesValidation)
                {
                        switch (eventName)
                        {
@@ -1643,7 +1784,7 @@ namespace System.Web.UI.WebControls
                                        
                        case DataControlCommands.UpdateCommandName:
                                int editIndex = int.Parse (param);
-                               UpdateRow (Rows [editIndex], editIndex, true);
+                               UpdateRow (Rows [editIndex], editIndex, causesValidation);
                                break;
                                        
                        case DataControlCommands.CancelCommandName:
@@ -1675,12 +1816,12 @@ namespace System.Web.UI.WebControls
                        OnSorting (args);
                        if (args.Cancel) return;
                        
-               if (IsBoundUsingDataSourceID) {
-                       EditIndex = -1;
-                       PageIndex = 0;
-                       SortExpression = args.SortExpression;
-                       SortDirection = args.SortDirection;
-               }
+                       if (IsBoundUsingDataSourceID) {
+                               EditIndex = -1;
+                               PageIndex = 0;
+                               SortExpression = args.SortExpression;
+                               SortDirection = args.SortDirection;
+                       }
                        
                        OnSorted (EventArgs.Empty);
                }
@@ -1690,6 +1831,7 @@ namespace System.Web.UI.WebControls
                        GridViewSelectEventArgs args = new GridViewSelectEventArgs (index);
                        OnSelectedIndexChanging (args);
                        if (!args.Cancel) {
+                               RequireBinding ();
                                SelectedIndex = args.NewSelectedIndex;
                                OnSelectedIndexChanged (EventArgs.Empty);
                        }
@@ -1741,12 +1883,11 @@ namespace System.Web.UI.WebControls
 
                void UpdateRow (GridViewRow row, int rowIndex, bool causesValidation)
                {
-                       if (causesValidation && Page != null)
-                               Page.Validate ();
-
-                       currentEditOldValues = OldEditValues.Values;
+                       if (causesValidation && Page != null && !Page.IsValid)
+                               return;
 
-                       currentEditRowKeys = DataKeys [rowIndex].Values;
+                       currentEditOldValues = CopyOrderedDictionary (OldEditValues.Values);
+                       currentEditRowKeys = CopyOrderedDictionary (DataKeys [rowIndex].Values);
                        currentEditNewValues = GetRowValues (row, false, false);
                        
                        GridViewUpdateEventArgs args = new GridViewUpdateEventArgs (rowIndex, currentEditRowKeys, currentEditOldValues, currentEditNewValues);
@@ -1761,6 +1902,14 @@ namespace System.Web.UI.WebControls
                        view.Update (currentEditRowKeys, currentEditNewValues, currentEditOldValues, new DataSourceViewOperationCallback (UpdateCallback));
                }
 
+               static IOrderedDictionary CopyOrderedDictionary (IOrderedDictionary sourceDic) {
+                       OrderedDictionary copyDic = new OrderedDictionary ();
+                       foreach (object key in sourceDic.Keys) {
+                               copyDic.Add (key, sourceDic [key]);
+                       }
+                       return copyDic;
+               }
+
                bool UpdateCallback (int recordsAffected, Exception exception)
                {
                        GridViewUpdatedEventArgs dargs = new GridViewUpdatedEventArgs (recordsAffected, exception, currentEditRowKeys, currentEditOldValues, currentEditNewValues);
@@ -1775,7 +1924,7 @@ namespace System.Web.UI.WebControls
                public virtual void DeleteRow (int rowIndex)
                {
                        GridViewRow row = Rows [rowIndex];
-                       currentEditRowKeys = DataKeys [rowIndex].Values;
+                       currentEditRowKeys = CopyOrderedDictionary (DataKeys [rowIndex].Values);
                        currentEditNewValues = GetRowValues (row, true, true);
                        
                        GridViewDeleteEventArgs args = new GridViewDeleteEventArgs (rowIndex, currentEditRowKeys, currentEditNewValues);
@@ -1998,9 +2147,12 @@ namespace System.Web.UI.WebControls
                
                protected virtual string GetCallbackScript (IButtonControl control, string argument)
                {
-                       if (EnableSortingAndPagingCallbacks)
+                       if (EnableSortingAndPagingCallbacks) {
+                               Page page = Page;
+                               if (page != null)
+                                       page.ClientScript.RegisterForEventValidation (UniqueID, argument);
                                return "javascript:GridView_ClientEvent (\"" + ClientID + "\",\"" + control.CommandName + "$" + control.CommandArgument + "\"); return false;";
-                       else
+                       else
                                return null;
                }
                
@@ -2018,24 +2170,34 @@ namespace System.Web.UI.WebControls
                                SortExpression = Page.Request.Form [ClientID + "_SortExpression"];
                        }
                }
-               
+
+
+               const string onPreRenderScript = @"var {0} = new Object ();
+{0}.pageIndex = {1};
+{0}.sortExp = {2};
+{0}.sortDir = {3};
+{0}.uid = {4};
+{0}.form = {5};
+";
                protected internal override void OnPreRender (EventArgs e)
                {
                        base.OnPreRender (e);
-                       
-                       if (EnableSortingAndPagingCallbacks)
-                       {
+
+                       if (EnableSortingAndPagingCallbacks) {
                                if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof(GridView), "GridView.js")) {
                                        string url = Page.ClientScript.GetWebResourceUrl (typeof(GridView), "GridView.js");
                                        Page.ClientScript.RegisterClientScriptInclude (typeof(GridView), "GridView.js", url);
                                }
                                
                                string cgrid = ClientID + "_data";
-                               string script = string.Format ("var {0} = new Object ();\n", cgrid);
-                               script += string.Format ("{0}.pageIndex = {1};\n", cgrid, ClientScriptManager.GetScriptLiteral (PageIndex));
-                               script += string.Format ("{0}.sortExp = {1};\n", cgrid, ClientScriptManager.GetScriptLiteral (SortExpression == null ? "" : SortExpression));
-                               script += string.Format ("{0}.sortDir = {1};\n", cgrid, ClientScriptManager.GetScriptLiteral ((int) SortDirection));
-                               script += string.Format ("{0}.uid = {1};\n", cgrid, ClientScriptManager.GetScriptLiteral (UniqueID));
+                               string script = String.Format (onPreRenderScript,
+                                                       cgrid,
+                                                       ClientScriptManager.GetScriptLiteral (PageIndex),
+                                                       ClientScriptManager.GetScriptLiteral (SortExpression == null ? "" : SortExpression),
+                                                       ClientScriptManager.GetScriptLiteral ((int) SortDirection),
+                                                       ClientScriptManager.GetScriptLiteral (UniqueID),
+                                                       Page.theForm);
+                               
                                Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
                                
                                // Make sure the basic script infrastructure is rendered
@@ -2043,11 +2205,10 @@ namespace System.Web.UI.WebControls
                                Page.ClientScript.GetPostBackClientHyperlink (this, "");
                        }
                }
-
+               
                protected internal override void Render (HtmlTextWriter writer)
                {
                        PrepareControlHierarchy ();
-
                        if (EnableSortingAndPagingCallbacks)
                                writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_div");
                        writer.RenderBeginTag (HtmlTextWriterTag.Div);