2009-05-26 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ContainerControl.cs
index b454df3c4ede858463bda833822099c612235d49..20a9425d41da1f448c7e3870dc8541734e28bc77 100644 (file)
@@ -39,6 +39,7 @@ namespace System.Windows.Forms {
        public class ContainerControl : ScrollableControl, IContainerControl {
                private Control         active_control;
                private Control         unvalidated_control;
+               private ArrayList       pending_validation_chain;
 
                // This is an internal hack that allows some container controls
                // to not auto select their child when they are activated
@@ -46,8 +47,13 @@ namespace System.Windows.Forms {
 #if NET_2_0
                private SizeF           auto_scale_dimensions;
                private AutoScaleMode   auto_scale_mode;
+               private bool            auto_scale_mode_set;
+               private bool            auto_scale_pending;
+               private bool            is_auto_scaling;
 #endif
 
+               internal bool validation_failed; //track whether validation was cancelled by a validating control
+
                #region Public Constructors
                public ContainerControl() {
                        active_control = null;
@@ -55,7 +61,7 @@ namespace System.Windows.Forms {
                        ControlRemoved += new ControlEventHandler(OnControlRemoved);
 #if NET_2_0
                        auto_scale_dimensions = SizeF.Empty;
-                       auto_scale_mode = AutoScaleMode.None;
+                       auto_scale_mode = AutoScaleMode.Inherit;
 #endif
                }
                #endregion      // Public Constructors
@@ -69,7 +75,7 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               if (value==null || (active_control == value)) {
+                               if (value==null || (active_control == value && active_control.Focused)) {
                                        return;
                                }
 
@@ -79,101 +85,202 @@ namespace System.Windows.Forms {
 
                                // Fire the enter and leave events if possible
                                Form form = FindForm ();
-                               if (form != null) {
-                                       Control active = GetMostDeeplyNestedActiveControl (form);
-                                       Control common_container = GetCommonContainer (active, value);
-                                       ArrayList chain = new ArrayList ();
-                                       ArrayList validation_chain = new ArrayList ();
-                                       Control walk = active;
-
-                                       // we split this up into three steps:
-                                       //    1. walk up the tree (if we need to) to our root, firing leave events.
-                                       //    2. validate.
-                                       //    3. walk down the tree (if we need to), firing enter events.
-
-                                       // "our root" is either the common container of the current active
-                                       // control and the new active control, or the current active control,
-                                       // or the new active control.  That is, it's either one of these three
-                                       // configurations:
-
-                                       //  (1)     root            (2)  new          (3)  current
-                                       //          /  \                /   \               /   \
-                                       //        ...   ...           ...   ...           ...   ...
-                                       //        /      \            /                           \
-                                       //     current   new       current                        new
-
-
-                                       // note (3) doesn't require any upward walking, and no leave events are generated.
-                                       //      (2) doesn't require any downward walking, and no enter events are generated.
-
-                                       // as we walk up the tree, we generate a list of all controls which cause
-                                       // validation.  After firing the leave events, we invoke (in order starting from
-                                       // the most deeply nested) their Validating event.  If one sets CancelEventArgs.Cancel
-                                       // to true, we ignore the control the user wanted to set ActiveControl to, and use
-                                       // the Validating control instead.
-
-                                       bool fire_enter = true;
-                                       Control root = common_container;
-
-                                       // Generate the leave messages
-                                       while (walk != common_container) {
-                                               if (walk == value) {
-                                                       root = value;
-                                                       fire_enter = false;
-                                                       break;
-                                               }
-                                               walk.FireLeave ();
-                                               /* clear our idea of the active control as we go back up */
-                                               if (walk is ContainerControl)
-                                                       ((ContainerControl)walk).active_control = null;
+                               Control active = GetMostDeeplyNestedActiveControl (form == null ? this : form);
+                               Control common_ancestor = GetCommonContainer (active, value);
+                               ArrayList chain = new ArrayList ();
+                               ArrayList validation_chain = new ArrayList ();
+                               Control walk = active;
+
+                               // we split this up into three steps:
+                               //    1. walk up the tree (if we need to) to our root, firing leave events.
+                               //    2. validate.
+                               //    3. walk down the tree (if we need to), firing enter events.
+
+                               // "our root" is either the common ancestor of the current active
+                               // control and the new active control, or the current active control,
+                               // or the new active control.  That is, it's either one of these three
+                               // configurations:
+
+                               //  (1)     root            (2)  new          (3)  current
+                               //          /  \                /   \               /   \
+                               //        ...   ...           ...   ...           ...   ...
+                               //        /      \            /                           \
+                               //     current   new       current                        new
+
+
+                               // note (3) doesn't require any upward walking, and no leave events are generated.
+                               //      (2) doesn't require any downward walking, and no enter events are generated.
+
+                               // as we walk up the tree, we generate a list of all controls which cause
+                               // validation.  After firing the leave events, we invoke (in order starting from
+                               // the most deeply nested) their Validating event.  If one sets CancelEventArgs.Cancel
+                               // to true, we ignore the control the user wanted to set ActiveControl to, and use
+                               // the Validating control instead.
+
+                               bool fire_enter = true;
+                               Control root = common_ancestor;
+
+                               active_control = value;
+
+                               // Generate the leave messages
+                               while (walk != common_ancestor && walk != null) {
+                                       if (walk == value) {
+                                               root = value;
+                                               fire_enter = false;
+                                               break;
+                                       }
+                                       walk.FireLeave ();
+                                       /* clear our idea of the active control as we go back up */
+                                       if (walk is ContainerControl)
+                                               ((ContainerControl)walk).active_control = null;
+
+                                       if (walk.CausesValidation)
+                                               validation_chain.Add (walk);
 
+                                       walk = walk.Parent;
+                               }
+
+                               // Validation can be postponed due to all the controls
+                               // in the enter chain not causing validation. If we don't have any
+                               // enter chain, it means that the selected control is a child and then
+                               // we need to validate the controls anyway
+                               bool postpone_validation;
+                               Control topmost_under_root = null; // topmost under root, in the *enter* chain
+                               if (value == root)
+                                       postpone_validation = false;
+                               else {
+                                       postpone_validation = true;
+                                       walk = value;
+                                       while (walk != root && walk != null) {
                                                if (walk.CausesValidation)
-                                                       validation_chain.Add (walk);
+                                                       postpone_validation = false;
 
+                                               topmost_under_root = walk;
                                                walk = walk.Parent;
                                        }
+                               }
 
-                                       for (int i = 0; i < validation_chain.Count; i ++) {
-                                               if (!ValidateControl ((Control)validation_chain[i])) {
-                                                       value = (Control)validation_chain[i];
-                                                       fire_enter = true;
-                                               }
+                               Control failed_validation_control = PerformValidation (form == null ? this : form, postpone_validation, 
+                                               validation_chain, topmost_under_root);
+                               if (failed_validation_control != null) {
+                                       active_control = value = failed_validation_control;
+                                       fire_enter = true;
+                               }
+
+                               if (fire_enter) {
+                                       walk = value;
+                                       while (walk != root && walk != null) {
+                                               chain.Add (walk);
+                                               walk = walk.Parent;
                                        }
 
-                                       if (fire_enter) {
-                                               walk = value;
-                                               while (walk != root) {
-                                                       chain.Add (walk);
-                                                       walk = walk.Parent;
-                                               }
+                                       if (root != null && walk == root && !(root is ContainerControl))
+                                               chain.Add (walk);
 
-                                               for (int i = chain.Count - 1; i >= 0; i--) {
-                                                       walk = (Control) chain [i];
-                                                       walk.FireEnter ();
-                                               }
+                                       for (int i = chain.Count - 1; i >= 0; i--) {
+                                               walk = (Control) chain [i];
+                                               walk.FireEnter ();
                                        }
+                               }
 
-                                       walk = this;
-                                       while (walk != null) {
-                                               if (walk.Parent is ContainerControl)
-                                                       ((ContainerControl)walk.Parent).active_control = walk;
-                                               walk = walk.Parent;
+                               walk = this;
+                               Control ctl = this;
+                               while (walk != null) {
+                                       if (walk.Parent is ContainerControl) {
+                                               ((ContainerControl) walk.Parent).active_control = ctl;
+                                               ctl = walk.Parent;
                                        }
+                                       walk = walk.Parent;
                                }
 
-                               active_control = value;
-
                                if (this is Form)
                                        CheckAcceptButton();
 
                                // Scroll control into view
                                ScrollControlIntoView(active_control);
-
+                               
+                               
+                               walk = this;
+                               ctl = this;
+                               while (walk != null) {
+                                       if (walk.Parent is ContainerControl) {
+                                               ctl = walk.Parent;
+                                       }
+                                       walk = walk.Parent;
+                               }
+                               
                                // Let the control know it's selected
-                               SendControlFocus (value);
+                               if (ctl.InternalContainsFocus)
+                                       SendControlFocus (active_control);
+                       }
+               }
+
+               // Return the control where validation failed, and null otherwise
+               // @topmost_under_root is the control under the root in the enter chain, if any
+               //
+               // The process of validation happens as described:
+               //
+               //      1. Iterate over the nodes in the enter chain (walk down), looking for any node
+               //      causing validation. If we can't find any, don't validate the current validation chain, but postpone it,
+               //      saving it in the top_container.pending_validation_chain field, since we need to keep track of it later.
+               //      If we have a previous pending_validation_chain, add the new nodes, making sure they are not repeated
+               //      (this is computed in ActiveControl and we receive if as the postpone_validation parameter).
+               //
+               //      2. If we found at least one node causing validation in the enter chain, try to validate the elements
+               //      in pending_validation_chain, if any. Then continue with the ones receives as parameters.
+               //
+               //      3. Return null if all the validation performed successfully, and return the control where the validation
+               //      failed otherwise.
+               //
+               private Control PerformValidation (ContainerControl top_container, bool postpone_validation, ArrayList validation_chain, 
+                               Control topmost_under_root)
+               {
+                       validation_failed = false;
+
+                       if (postpone_validation) {
+                               AddValidationChain (top_container, validation_chain);
+                               return null;
+                       }
+
+                       // if not null, pending chain has always one element or more
+                       if (top_container.pending_validation_chain != null) {
+                               // if the topmost node in the enter chain is exactly the topmost
+                               // int the validation chain, remove it, as .net does
+                               int last_idx = top_container.pending_validation_chain.Count - 1;
+                               if (topmost_under_root == top_container.pending_validation_chain [last_idx])
+                                       top_container.pending_validation_chain.RemoveAt (last_idx);
+
+                               AddValidationChain (top_container, validation_chain);
+                               validation_chain = top_container.pending_validation_chain;
+                               top_container.pending_validation_chain = null;
                        }
+
+                       for (int i = 0; i < validation_chain.Count; i ++) {
+                               if (!ValidateControl ((Control)validation_chain[i])) {
+                                       validation_failed = true;
+                                       return (Control)validation_chain[i];
+                               }
+                       }
+
+                       return null;
                }
 
+               // Add the elements in validation_chain to the pending validation chain stored in top_container
+               private void AddValidationChain (ContainerControl top_container, ArrayList validation_chain)
+               {
+                       if (validation_chain.Count == 0)
+                               return;
+
+                       if (top_container.pending_validation_chain == null || top_container.pending_validation_chain.Count == 0) {
+                               top_container.pending_validation_chain = validation_chain;
+                               return;
+                       }
+
+                       foreach (Control c in validation_chain)
+                               if (!top_container.pending_validation_chain.Contains (c))
+                                       top_container.pending_validation_chain.Add (c);
+               }       
+
                private bool ValidateControl (Control c)
                {
                        CancelEventArgs e = new CancelEventArgs ();
@@ -237,22 +344,25 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               auto_scale_dimensions = value;
+                               if (auto_scale_dimensions != value) {
+                                       auto_scale_dimensions = value;
+                                       
+                                       PerformAutoScale ();
+                               }
                        }
                }
 
                protected SizeF AutoScaleFactor {
                        get {
-                               if (auto_scale_dimensions.IsEmpty) {
-                                       return new SizeF(1f, 1f);
-                               }
+                               if (auto_scale_dimensions.IsEmpty)
+                                       return new SizeF (1f, 1f);
+
                                return new SizeF(CurrentAutoScaleDimensions.Width / auto_scale_dimensions.Width,
                                        CurrentAutoScaleDimensions.Height / auto_scale_dimensions.Height);
                        }
                }
 
 
-               [MonoTODO("Call scaling method")]
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -261,10 +371,18 @@ namespace System.Windows.Forms {
                                return auto_scale_mode;
                        }
                        set {
+                               if (this is Form)
+                                       (this as Form).AutoScale = false;
+
                                if (auto_scale_mode != value) {
                                        auto_scale_mode = value;
 
-                                       // Trigger scaling
+                                       if (auto_scale_mode_set)
+                                               auto_scale_dimensions = SizeF.Empty;
+
+                                       auto_scale_mode_set = true;
+
+                                       PerformAutoScale ();
                                }
                        }
                }
@@ -285,30 +403,19 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               [MonoTODO("Revisit when System.Drawing.GDI.WindowsGraphics.GetTextMetrics is done or come up with other cross-plat avg. font width calc method")]
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                public SizeF CurrentAutoScaleDimensions {
                        get {
                                switch(auto_scale_mode) {
-                                       case AutoScaleMode.Dpi: {
-                                               Bitmap          bmp;
-                                               Graphics        g;
-                                               SizeF           size;
-
-                                               bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
-                                               g = Graphics.FromImage(bmp);
-                                               size = new SizeF(g.DpiX, g.DpiY);
-                                               g.Dispose();
-                                               bmp.Dispose();
-                                               return size;
-                                       }
-
-                                       case AutoScaleMode.Font: {
-                                               // http://msdn2.microsoft.com/en-us/library/system.windows.forms.containercontrol.currentautoscaledimensions(VS.80).aspx
-                                               // Implement System.Drawing.GDI.WindowsGraphics.GetTextMetrics first...
-                                               break;
-                                       }
+                                       case AutoScaleMode.Dpi:
+                                               return TextRenderer.GetDpi ();
+
+                                       case AutoScaleMode.Font:
+                                               Size s = TextRenderer.MeasureText ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", Font);
+                                               int width = (int)Math.Round ((float)s.Width / 62f);
+                                               
+                                               return new SizeF (width, s.Height);
                                }
 
                                return auto_scale_dimensions;
@@ -337,6 +444,11 @@ namespace System.Windows.Forms {
                #endregion      // Public Instance Properties
 
                #region Protected Instance Methods
+#if NET_2_0
+               protected override bool CanEnableIme {
+                       get { return false; }
+               }
+#endif
                protected override CreateParams CreateParams {
                        get {
                                return base.CreateParams;
@@ -345,7 +457,54 @@ namespace System.Windows.Forms {
                #endregion      // Public Instance Methods
 
                #region Public Instance Methods
-               [MonoTODO]
+#if NET_2_0
+               internal void PerformAutoScale (bool called_by_scale)
+               {
+                       if ((AutoScaleMode == AutoScaleMode.Inherit) && !called_by_scale)
+                               return;
+
+                       if ((layout_suspended > 0) && !called_by_scale) {
+                               auto_scale_pending = true;
+                               return;
+                       }
+                       // Set this first so we don't get called again from
+                       // PerformDelayedAutoScale after ResumeLayout
+                       auto_scale_pending = false;
+
+                       SizeF factor = AutoScaleFactor;
+                       if (AutoScaleMode == AutoScaleMode.Inherit) {
+                               ContainerControl cc = FindContainer (this.Parent);
+                               if (cc != null)
+                                       factor = cc.AutoScaleFactor;
+                       }
+                       if (factor != new SizeF (1F, 1F)) {
+                               is_auto_scaling = true;
+                               SuspendLayout ();
+                               Scale (factor);
+                               ResumeLayout (false);
+                               is_auto_scaling = false;
+                       }
+
+                       auto_scale_dimensions = CurrentAutoScaleDimensions;
+               }
+
+               public void PerformAutoScale ()
+               {
+                       PerformAutoScale (false);
+               }
+
+               internal void PerformDelayedAutoScale ()
+               {
+                       if (auto_scale_pending)
+                               PerformAutoScale ();
+               }
+
+               internal bool IsAutoScaling {
+                       get { return is_auto_scaling; }
+               }
+#endif
+
+               [MonoTODO ("Stub, not implemented")]
                static bool ValidateWarned;
                public bool Validate() {
                        //throw new NotImplementedException();
@@ -356,6 +515,36 @@ namespace System.Windows.Forms {
                        return true;
                }
 
+#if NET_2_0
+               public bool Validate (bool checkAutoValidate)
+               {
+                       if ((checkAutoValidate && (AutoValidate != AutoValidate.Disable)) || !checkAutoValidate)
+                               return Validate ();
+                               
+                       return true;
+               }
+               
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public virtual bool ValidateChildren ()
+               {
+                       return ValidateChildren (ValidationConstraints.Selectable);
+               }
+
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public virtual bool ValidateChildren (ValidationConstraints validationConstraints)
+               {
+                       bool recurse = !((validationConstraints & ValidationConstraints.ImmediateChildren) == ValidationConstraints.ImmediateChildren);
+                       
+                       foreach (Control control in Controls)
+                               if (!ValidateNestedControls (control, validationConstraints, recurse))
+                                       return false;
+
+                       return true;
+               }
+#endif
+
                bool IContainerControl.ActivateControl(Control control) {
                        return Select(control);
                }
@@ -393,6 +582,16 @@ namespace System.Windows.Forms {
                        OnBindingContextChanged (EventArgs.Empty);
                }
 
+#if NET_2_0
+               protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
+               {
+                       if (ToolStripManager.ProcessCmdKey (ref msg, keyData) == true)
+                               return true;
+                               
+                       return base.ProcessCmdKey (ref msg, keyData);
+               }
+#endif
+
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                protected override bool ProcessDialogChar(char charCode) {
                        if (GetTopLevel()) {
@@ -412,8 +611,10 @@ namespace System.Windows.Forms {
 
                        switch (key) {
                                case Keys.Tab: {
-                                       if (ProcessTabKey((Control.ModifierKeys & Keys.Shift) == 0)) {
-                                               return true;
+                                       if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) {
+                                               if (ProcessTabKey ((Control.ModifierKeys & Keys.Shift) == 0)) {
+                                                       return true;
+                                               }
                                        }
                                        break;
                                }
@@ -454,7 +655,7 @@ namespace System.Windows.Forms {
                                c = GetNextControl(c, true);
                                if (c != null) {
                                        // This is stupid. I want to be able to call c.ProcessMnemonic directly
-                                       if (c.CanSelect && c.ProcessControlMnemonic(charCode)) {
+                                       if (c.ProcessControlMnemonic(charCode)) {
                                                return(true);
                                        }
                                        continue;
@@ -495,12 +696,6 @@ namespace System.Windows.Forms {
                protected override void WndProc(ref Message m) {
                        switch ((Msg) m.Msg) {
 
-                               case Msg.WM_LBUTTONDOWN:
-                                       OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()),
-                                               mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()),
-                                               HighOrder ((int) m.LParam.ToInt32 ()), 0));
-                               break;
-
                                case Msg.WM_SETFOCUS:
                                        if (active_control != null)
                                                Select (active_control);
@@ -520,10 +715,100 @@ namespace System.Windows.Forms {
                #endregion      // Protected Instance Methods
 
                #region Internal Methods
+               internal void ChildControlRemoved (Control control)
+               {
+                       ContainerControl top_container = FindForm ();
+                       if (top_container == null)
+                               top_container = this;
+
+                       // Remove controls -as well as any sub control- that was in the pending validation chain
+                       ArrayList pending_validation_chain = top_container.pending_validation_chain;
+                       if (pending_validation_chain != null) {
+                               RemoveChildrenFromValidation (pending_validation_chain, control);
+
+                               if (pending_validation_chain.Count == 0)
+                                       top_container.pending_validation_chain = null;
+                       }
+
+                       if (control == active_control || control.Contains (active_control)) {
+                               SelectNextControl (this, true, true, true, true);
+                               if (control == active_control || control.Contains (active_control)) {
+                                       active_control = null;
+                               }
+                       }
+               }
+
+               // Check that this control (or any child) is included in the pending validation chain
+               bool RemoveChildrenFromValidation (ArrayList validation_chain, Control c)
+               {
+                       if (RemoveFromValidationChain (validation_chain, c))
+                               return true;
+
+                       foreach (Control child in c.Controls)
+                               if (RemoveChildrenFromValidation (validation_chain, child))
+                                       return true;
+
+                       return false;
+               }
+
+               // Remove the top most control in the pending validation chain, as well as any children there,
+               // taking advantage of the fact that the chain is in reverse order of the control's hierarchy
+               bool RemoveFromValidationChain (ArrayList validation_chain, Control c)
+               {
+                       int idx = validation_chain.IndexOf (c);
+                       if (idx > -1) {
+                               pending_validation_chain.RemoveAt (idx--);
+                               return true;
+                       }
+
+                       return false;
+               }
+
                internal virtual void CheckAcceptButton()
                {
                        // do nothing here, only called if it is a Form
                }
+
+#if NET_2_0
+               private bool ValidateNestedControls (Control c, ValidationConstraints constraints, bool recurse)
+               {
+                       bool validate_result = true;
+
+                       if (!c.CausesValidation)
+                               validate_result = true;
+                       else if (!ValidateThisControl (c, constraints))
+                               validate_result = true;
+                       else if (!ValidateControl (c))
+                               validate_result = false;
+
+                       if (recurse)
+                               foreach (Control control in c.Controls)
+                                       if (!ValidateNestedControls (control, constraints, recurse))
+                                               return false;
+
+                       return validate_result;
+               }
+
+               private bool ValidateThisControl (Control c, ValidationConstraints constraints)
+               {
+                       if (constraints == ValidationConstraints.None)
+                               return true;
+
+                       if ((constraints & ValidationConstraints.Enabled) == ValidationConstraints.Enabled && !c.Enabled)
+                               return false;
+
+                       if ((constraints & ValidationConstraints.Selectable) == ValidationConstraints.Selectable && !c.GetStyle (ControlStyles.Selectable))
+                               return false;
+
+                       if ((constraints & ValidationConstraints.TabStop) == ValidationConstraints.TabStop && !c.TabStop)
+                               return false;
+
+                       if ((constraints & ValidationConstraints.Visible) == ValidationConstraints.Visible && !c.Visible)
+                               return false;
+
+                       return true;
+               }
+#endif
                #endregion      // Internal Methods
 
 #if NET_2_0
@@ -536,9 +821,21 @@ namespace System.Windows.Forms {
                protected override void OnFontChanged (EventArgs e)
                {
                        base.OnFontChanged (e);
+                       
+                       if (AutoScaleMode == AutoScaleMode.Font)
+                               PerformAutoScale ();
                }
 
+               protected override void OnLayout (LayoutEventArgs e)
+               {
+                       base.OnLayout (e);
+               }
+               
                AutoValidate auto_validate = AutoValidate.Inherit;
+
+               [Browsable (false)]
+               [AmbientValue (AutoValidate.Inherit)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
                public virtual AutoValidate AutoValidate {
                        get {
                                return auto_validate;
@@ -553,6 +850,11 @@ namespace System.Windows.Forms {
                        }
                }
 
+               internal bool ShouldSerializeAutoValidate ()
+               {
+                       return this.AutoValidate != AutoValidate.Inherit;
+               }
+
                static object OnValidateChanged = new object ();
 
                protected virtual void OnAutoValidateChanged (EventArgs e)
@@ -562,6 +864,8 @@ namespace System.Windows.Forms {
                                eh (this, e);
                }
 
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
                public event EventHandler AutoValidateChanged {
                        add { Events.AddHandler (OnValidateChanged, value); }
                        remove { Events.RemoveHandler (OnValidateChanged, value); }