ContainerControl.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / ContainerControl.cs / 1305376 / ContainerControl.cs

                            //---------------------------------------------------------------------------- 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Threading; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Collections.Specialized;
    using System.ComponentModel; 
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis; 
    using System; 
    using System.Drawing;
    using System.ComponentModel.Design; 
    using System.Windows.Forms.Layout;
    using System.Windows.Forms.Internal;
    using Microsoft.Win32;
    using System.Security; 
    using System.Security.Permissions;
 
    ///  
    /// 
    ///    Defines a 
    ///       base class for
    ///       controls that can parent other controls.
    /// 
    [ComVisible(true), 
     ClassInterface(ClassInterfaceType.AutoDispatch)
    ] 
    public class ContainerControl : ScrollableControl, IContainerControl { 
        private Control activeControl; // current active control
        private Control focusedControl; // Current focused control. Do not directly edit this value. 
        private Control unvalidatedControl; // The last control that requires validation.  Do not directly edit this value.
        private AutoValidate autoValidate = AutoValidate.Inherit; // Indicates whether automatic validation is turned on.
        private EventHandler autoValidateChanged; // Event fired whenever the AutoValidate property changes.
 
        // Auto scaling property values
        private SizeF autoScaleDimensions = SizeF.Empty; 
        private SizeF currentAutoScaleDimensions = SizeF.Empty; 
        private AutoScaleMode autoScaleMode = AutoScaleMode.Inherit;
        private BitVector32 state = new BitVector32(); 

        private static readonly int stateScalingNeededOnLayout = BitVector32.CreateMask(); // True if we need to perform scaling when layout resumes
        private static readonly int stateValidating            = BitVector32.CreateMask(stateScalingNeededOnLayout); // Indicates whether we're currently state[stateValidating].
        private static readonly int stateProcessingMnemonic    = BitVector32.CreateMask(stateValidating); // Indicates whether we or one of our children is currently processing a mnemonic. 
        private static readonly int stateScalingChild          = BitVector32.CreateMask(stateProcessingMnemonic); // True while we are scaling a child control
        private static readonly int stateParentChanged         = BitVector32.CreateMask(stateScalingChild); // Flagged when a parent changes so we can adpat our scaling logic to match 
 
        private static readonly int PropAxContainer            = PropertyStore.CreateKey();
        private const string fontMeasureString                 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

        /// 
        /// 
        /// Initializes a new instance of the  
        /// class.
        ///  
        public ContainerControl() : base() { 
            SetStyle(ControlStyles.AllPaintingInWmPaint, false);
 
            // this class overrides GetPreferredSizeCore, let Control automatically cache the result
            SetState2(STATE2_USEPREFERREDSIZECACHE, true);
        }
 
        /// 
        ///  
        ///     AutoScaleDimensions represents the DPI or Font setting that the control has been scaled 
        ///     to or designed at. Specifically, at design time this property will be set by the
        ///     designer to the value that the developer is designing at. Then, at runtime, when the 
        ///     form loads if the CurrentAutoScaleDimensions are different from the AutoScaleDimensions,
        ///     PerformAutoScale will be called and AutoScaleDimensions will be set to the new value to
        ///     match the CurrentAutoScaleDimensions by PerformAutoScale.
        ///  
        [Localizable(true)]
        [Browsable(false)] 
        [SRCategory(SR.CatLayout)] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public SizeF AutoScaleDimensions {
            get {
                return autoScaleDimensions;
            } 
            [
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // value is the name of the param passed in. 
                                                                                                            // So we don't have to localize it. 
            ]
            set { 
                if (value.Width < 0 || value.Height < 0) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.ContainerControlInvalidAutoScaleDimensions), "value");
                }
                autoScaleDimensions = value; 
                if (!autoScaleDimensions.IsEmpty) {
                    LayoutScalingNeeded(); 
                } 
            }
        } 

        /// 
        /// 
        ///     AutoScaleFactor represents the scaling factor difference between 
        ///     CurrentAutoScaleDimensions and AutoScaleDimensions. This value is
        ///     calculated on the fly. Eg: If CurrentAutoScaleDimensions is 192, 192 
        ///     and AutoScaleDimensions is 96, 96 then the AutoScaleFactor is 2.0, 2.0 
        /// 
        protected SizeF AutoScaleFactor { 
            get {
                SizeF current = CurrentAutoScaleDimensions;
                SizeF saved = AutoScaleDimensions;
 
                // If no one has configured auto scale dimensions yet, the scaling factor
                // is unity. 
                if (saved.IsEmpty) { 
                    return new SizeF(1.0F, 1.0F);
                } 

                return new SizeF(current.Width / saved.Width, current.Height / saved.Height);
            }
        } 

        ///  
        ///  
        ///     Determines the scaling mode of this control.  The default is no scaling.
        /// 
        ///     Scaling by Font is useful if you wish to have a control
        ///     or form stretch or shrink according to the size of the fonts in the system, and should
        ///     be used when the control or form's size itself does not matter.
        /// 
        ///     Scaling by DPI is useful when you wish to keep a control or form a specific size
        ///     independent of font.  for example, a control displaying a chart or other graphic 
        ///     may want to use DPI scaling to increase in size to account for higher DPI monitors. 
        /// 
        [SRCategory(SR.CatLayout)] 
        [SRDescription(SR.ContainerControlAutoScaleModeDescr)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public AutoScaleMode AutoScaleMode {
            get { 
                return autoScaleMode; 
            }
            set { 
                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)AutoScaleMode.None, (int)AutoScaleMode.Inherit)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(AutoScaleMode));
                } 

                bool scalingNeeded = false; 
 
                if (value != autoScaleMode) {
 
                    // Invalidate any current scaling factors.  If we
                    // are changing AutoScaleMode to anything other than
                    // its default, we should clear out autoScaleDimensions as it is
                    // nonsensical. 
                    if (autoScaleMode != AutoScaleMode.Inherit) {
                        autoScaleDimensions = SizeF.Empty; 
                    } 

                    currentAutoScaleDimensions = SizeF.Empty; 
                    autoScaleMode = value;
                    scalingNeeded = true;
                }
 
                OnAutoScaleModeChanged();
 
                if (scalingNeeded) { 
                    LayoutScalingNeeded();
                } 
            }
        }

        ///  
        /// 
        ///     Indicates whether controls in this container will be automatically validated when the focus changes. 
        ///  
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        AmbientValue(AutoValidate.Inherit),
        SRCategory(SR.CatBehavior),
        SRDescription(SR.ContainerControlAutoValidate), 
        ]
        public virtual AutoValidate AutoValidate { 
            get { 
                if (autoValidate == AutoValidate.Inherit) {
                    return GetAutoValidateForControl(this); 
                }
                else {
                    return autoValidate;
                } 
            }
            set { 
                // PERF/FXCop: dont use Enum.IsDefined. 
                switch (value) {
                    case AutoValidate.Disable: 
                    case AutoValidate.EnablePreventFocusChange:
                    case AutoValidate.EnableAllowFocusChange:
                    case AutoValidate.Inherit:
                        break; 
                    default:
                        throw new InvalidEnumArgumentException("AutoValidate", (int) value, typeof(AutoValidate)); 
                } 

                if (autoValidate != value) { 
                    autoValidate = value;
                    OnAutoValidateChanged(EventArgs.Empty);
                }
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        SRCategory(SR.CatPropertyChanged),
        SRDescription(SR.ContainerControlOnAutoValidateChangedDescr), 
        ] 
        public event EventHandler AutoValidateChanged {
            add { 
                this.autoValidateChanged += value;
            }
            remove {
                this.autoValidateChanged -= value; 
            }
        } 
 
        /// 
        ///  
        /// 
        ///    
        ///       The binding manager for the container control.
        ///     
        /// 
        [ 
        Browsable(false), 
        SRDescription(SR.ContainerControlBindingContextDescr)
        ] 
        public override BindingContext BindingContext {
            get {
                BindingContext bm = base.BindingContext;
                if (bm == null) { 
                    bm = new BindingContext();
                    BindingContext = bm; 
                } 
                return bm;
            } 
            set {
                base.BindingContext = value;
            }
        } 

        ///  
        ///     Container controls support ImeMode only to allow child controls to inherit it from their parents. 
        /// 
        protected override bool CanEnableIme { 
            get {
                // Note: If overriding this property make sure to copy the Debug code and call this method.

                Debug.Indent(); 
                Debug.WriteLineIf( CompModSwitches.ImeMode.Level >= TraceLevel.Info, "Inside get_CanEnableIme(), value = false" + ", this = " + this );
                Debug.Unindent(); 
 
                return false;
            } 
        }

        /// 
        ///  
        ///    Indicates the current active control on the container control.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ContainerControlActiveControlDescr)
        ]
        public Control ActiveControl { 
            get {
                return activeControl; 
            } 

            set { 
                SetActiveControl(value);
            }
        }
 
        /// 
        protected override CreateParams CreateParams { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
            get {
                CreateParams cp = base.CreateParams; 
                cp.ExStyle |= NativeMethods.WS_EX_CONTROLPARENT;
                return cp;
            }
        } 

        ///  
        ///  
        ///     CurrentAutoScaleDimensions represent the actual DPI or Font settings
        ///     of the display at runtime. If the AutoScaleMode is set to �None� then 
        ///     the CurrentAutoScaleDimensions is equal to the ActualScaleDimensions
        /// 
        [Browsable(false)]
        [SRCategory(SR.CatLayout)] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public SizeF CurrentAutoScaleDimensions { 
            get { 
                if (currentAutoScaleDimensions.IsEmpty) {
                    switch (AutoScaleMode) { 
                        case AutoScaleMode.Font:
                            currentAutoScaleDimensions = GetFontAutoScaleDimensions();
                            break;
 
                        case AutoScaleMode.Dpi:
                            // Screen Dpi 
                            currentAutoScaleDimensions = WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.Dpi; 
                            break;
 
                        default:
                            currentAutoScaleDimensions = AutoScaleDimensions;
                            break;
                    } 
                }
 
                return currentAutoScaleDimensions; 
            }
        } 

        /// 
        /// 
        ///    Indicates the form that the scrollable control is assigned to. This property is read-only. 
        /// 
        [ 
        SRCategory(SR.CatAppearance), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.ContainerControlParentFormDescr)
        ]
        public Form ParentForm {
            get { 
                Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "GetParent Demanded");
                IntSecurity.GetParent.Demand(); 
                return ParentFormInternal; 
            }
        } 

        internal Form ParentFormInternal {
            get {
                if (ParentInternal != null) { 
                    return ParentInternal.FindFormInternal();
                } 
                else { 
                    if (this is Form) {
                        return null; 
                    }

                    return FindFormInternal();
                } 
            }
        } 
 
        // Package scope for Control
        ///  
        /// 
        /// 
        /// Activates the specified control.
        ///  
        bool IContainerControl.ActivateControl(Control control) {
            Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ModifyFocus Demanded"); 
            IntSecurity.ModifyFocus.Demand(); 

            return ActivateControlInternal(control, true); 
        }

        internal bool ActivateControlInternal(Control control) {
            return ActivateControlInternal(control, true); 
        }
 
        internal bool ActivateControlInternal(Control control, bool originator) { 
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::ActivateControlInternal(" + (control == null ? "null" : control.Name) + "," + originator.ToString() + ") - " + this.Name);
            // Recursive function that makes sure that the chain of active controls 
            // is coherent.
            bool ret = true;
            bool updateContainerActiveControl = false;
            ContainerControl cc = null; 
            Control parent = this.ParentInternal;
            if (parent != null) 
            { 
                cc = (parent.GetContainerControlInternal()) as ContainerControl;
                if (cc != null) 
                {
                    updateContainerActiveControl = (cc.ActiveControl != this);
                }
            } 
            if (control != activeControl || updateContainerActiveControl)
            { 
                if (updateContainerActiveControl) 
                {
                    if (!cc.ActivateControlInternal(this, false)) 
                    {
                        return false;
                    }
                } 
                ret = AssignActiveControlInternal((control == this) ? null : control);
            } 
 
            if (originator) {
                ScrollActiveControlIntoView(); 
            }
            return ret;
        }
 
        /// 
        ///  
        ///     Used for UserControls - checks if the control 
        ///     has a focusable control inside or not
        ///  
        internal bool HasFocusableChild()
        {
            Control ctl = null;
            do { 
                ctl = GetNextControl(ctl, true);
                if (ctl != null && 
                    ctl.CanSelect && 
                    ctl.TabStop)
                { 
                    break;
                }
            } while (ctl != null);
            return ctl != null; 
        }
 
        ///  
        /// 
        ///  
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override void AdjustFormScrollbars(bool displayScrollbars) {
            base.AdjustFormScrollbars(displayScrollbars); 

            if (!GetScrollState(ScrollStateUserHasScrolled)) { 
                ScrollActiveControlIntoView(); 
            }
        } 

        /// 
        ///     Cleans up form state after a control has been removed.
        ///     Package scope for Control 
        /// 
        ///  
        internal virtual void AfterControlRemoved(Control control, Control oldParent) { 
            ContainerControl cc;
            Debug.Assert(control != null); 
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::AfterControlRemoved(" + control.Name + ") - " + this.Name);
            if (control == activeControl || control.Contains(activeControl)) {
                bool selected;
                // SECREVIEW : Note that a function overriding "protected virtual void Control::Select(bool directed, bool forward)" 
                //             called by SelectNextControl will be able to set the focus to any control.
                //             This is also enabled by the ModifyFocus.Assert inside Control::SelectNextIfFocused. 
                IntSecurity.ModifyFocus.Assert (); 
                try
                { 
                    selected = SelectNextControl(control, true, true, true, true);
                }
                finally
                { 
                    CodeAccessPermission.RevertAssert ();
                } 
                if (selected) 
                {
                    FocusActiveControlInternal(); 
                }
                else
                {
                    SetActiveControlInternal(null); 
                }
            } 
            else if (activeControl == null && ParentInternal != null) 
            {
                // The last control of an active container was removed. Focus needs to be given to the next 
                // control in the Form.
                cc = ParentInternal.GetContainerControlInternal() as ContainerControl;
                if (cc != null && cc.ActiveControl == this)
                { 
                    Form f = FindFormInternal();
                    if (f != null) 
                    { 
                        // SECREVIEW : Same comment as above.
                        IntSecurity.ModifyFocus.Assert (); 
                        try
                        {
                            f.SelectNextControl(this, true, true, true, true);
                        } 
                        finally
                        { 
                            CodeAccessPermission.RevertAssert(); 
                        }
                    } 
                }
            }

            // VSWhidbey#262686: Two controls in UserControls that don't take focus via UI can have bad behavior if ... 
            // VSWhidbey#537131:
            // When a control is removed from a container, not only do we need to clear the unvalidatedControl of that 
            // container potentially, but the unvalidatedControl of all its container parents, up the chain, needs to 
            // now point to the old parent of the disappearing control.
            cc = this; 
            while (cc != null) {
                Control parent = cc.ParentInternal;
                if (parent == null) {
                    break; 
                }
                else { 
                    cc = parent.GetContainerControlInternal() as ContainerControl; 
                }
                if (cc != null && 
                    cc.unvalidatedControl != null &&
                    (cc.unvalidatedControl == control || control.Contains(cc.unvalidatedControl)))
                {
                    cc.unvalidatedControl = oldParent; 
                }
            } 
 
            if (control == unvalidatedControl || control.Contains(unvalidatedControl)) {
                unvalidatedControl = null; 
            }
        }

        private bool AssignActiveControlInternal(Control value) { 
#if DEBUG
            if (value == null || (value != null && value.ParentInternal != null && !value.ParentInternal.IsContainerControl)) 
            { 
                Debug.Assert(value == null || (value.ParentInternal != null && this == value.ParentInternal.GetContainerControlInternal()));
            } 
#endif

            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::AssignActiveControlInternal(" + (value == null ? "null" : value.Name) + ") - " + this.Name);
            if (activeControl != value) { 
                // cpb: #7318
#if FALSE 
                if (activeControl != null) { 
                    AxHost.Container cont = FindAxContainer();
                    if (cont != null) { 
                        cont.OnOldActiveControl(activeControl, value);
                    }
                }
#endif 
                try {
                    if (value != null) { 
                        value.BecomingActiveControl = true; 
                    }
                    activeControl = value; 
                    UpdateFocusedControl();
                }
                finally {
                    if (value != null) { 
                        value.BecomingActiveControl = false;
                    } 
                } 
                if (activeControl == value) {
                    // cpb: #7318 
#if FALSE
                    AxHost.Container cont = FindAxContainer();
                    if (cont != null) {
                        cont.OnNewActiveControl(value); 
                    }
#endif 
                    Form form = FindFormInternal(); 
                    if (form != null)
                    { 
                        form.UpdateDefaultButton();
                    }
                }
            } 
            else {
                focusedControl = activeControl; 
            } 
            return(activeControl == value);
        } 

        /// 
        ///     Used to notify the AxContainer that the form
        ///     has been created.  This should only be called if 
        ///     there is an AX container.
        ///  
        private void AxContainerFormCreated() { 
            ((AxHost.AxContainer)Properties.GetObject(PropAxContainer)).FormCreated();
        } 

        /// 
        ///     Specifies whether this control can process the mnemonic or not.
        ///  
        internal override bool CanProcessMnemonic() {
#if DEBUG 
            TraceCanProcessMnemonic(); 
#endif
            if( this.state[stateProcessingMnemonic]){ 
                return true;
            }

            return base.CanProcessMnemonic(); 
        }
 
        internal AxHost.AxContainer CreateAxContainer() { 
            object aXContainer = Properties.GetObject(PropAxContainer);
            if (aXContainer == null) { 
                aXContainer = new AxHost.AxContainer(this);
                Properties.SetObject(PropAxContainer, aXContainer);
            }
            return(AxHost.AxContainer)aXContainer; 
        }
 
        ///  
        /// 
        ///    Disposes of the resources (other than memory) used by 
        ///       the 
        ///       .
        /// 
        protected override void Dispose(bool disposing) { 
            if (disposing) {
                activeControl = null; 
            } 

            base.Dispose(disposing); 

            focusedControl = null;
            unvalidatedControl = null;
        } 

        ///  
        ///     Recursively enables required scaling from the given control 
        /// 
        private void EnableRequiredScaling(Control start, bool enable) { 
            start.RequiredScalingEnabled = enable;
            foreach(Control c in start.Controls) {
                EnableRequiredScaling(c, enable);
            } 
        }
 
        ///  
        ///     Assigns focus to the activeControl. If there is no activeControl then
        ///     focus is given to the form. 
        ///     package scope for Form
        /// 
        internal void FocusActiveControlInternal() {
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::FocusActiveControlInternal() - " + this.Name); 
#if DEBUG
            // Things really get ugly if you try to pop up an assert dialog here 
            if (activeControl != null && !this.Contains(activeControl)) 
                Debug.WriteLine("ActiveControl is not a child of this ContainerControl");
#endif 

            if (activeControl != null && activeControl.Visible) {

                // Avoid focus loops, especially with ComboBoxes, on Win98/ME. 
                //
                IntPtr focusHandle = UnsafeNativeMethods.GetFocus(); 
                if (focusHandle == IntPtr.Zero || Control.FromChildHandleInternal(focusHandle) != activeControl) { 
                    UnsafeNativeMethods.SetFocus(new HandleRef(activeControl, activeControl.Handle));
                } 
            }
            else {
                // Determine and focus closest visible parent
                ContainerControl cc = this; 
                while (cc != null && !cc.Visible)
                { 
                    Control parent = cc.ParentInternal; 
                    if (parent != null)
                    { 
                        cc = parent.GetContainerControlInternal() as ContainerControl;
                    }
                    else {
                        break; 
                    }
                } 
                if (cc != null && cc.Visible) 
                {
                    UnsafeNativeMethods.SetFocus(new HandleRef(cc, cc.Handle)); 
                }
            }
        }
 

        internal override Size GetPreferredSizeCore(Size proposedSize) { 
            // Translating 0,0 from ClientSize to actual Size tells us how much space 
            // is required for the borders.
            Size borderSize = SizeFromClientSize(Size.Empty); 
            Size totalPadding = borderSize + Padding.Size;
            return LayoutEngine.GetPreferredSize(this, proposedSize - totalPadding) + totalPadding;
        }
 
        /// 
        ///     This method calcuates the auto scale dimensions based on the 
        ///     control's current font. 
        /// 
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")] // Refers to 'fontMeasureString'. 
        [SuppressMessage("Microsoft.Usage", "CA2204:LiteralsShouldBeSpelledCorrectly")]
        private SizeF GetFontAutoScaleDimensions()
        {
            SizeF retval = SizeF.Empty; 

            // Windows uses CreateCompatibleDC(NULL) to get a 
            // memory DC for the monitor the application is currently 
            // on.
            IntPtr dc = UnsafeNativeMethods.CreateCompatibleDC(NativeMethods.NullHandleRef); 
            if (dc == IntPtr.Zero) {
                throw new Win32Exception();
            }
 
            HandleRef hdc = new HandleRef(this, dc);
 
            try { 
                // We clone the Windows scaling function here as closely as
                // possible.  They use textmetric for height, and textmetric 
                // for width of fixed width fonts.  For variable width fonts
                // they use GetTextExtentPoint32 and pass in a long a-Z string.
                // We must do the same here if our dialogs are to scale in a
                // similar fashion. 

                HandleRef hfont = new HandleRef(this, FontHandle); 
                HandleRef hfontOld = new HandleRef(this, SafeNativeMethods.SelectObject(hdc, hfont)); 

                try { 
                    NativeMethods.TEXTMETRIC tm = new NativeMethods.TEXTMETRIC();
                    SafeNativeMethods.GetTextMetrics(hdc, ref tm);

                    retval.Height = tm.tmHeight; 

                    if ((tm.tmPitchAndFamily & NativeMethods.TMPF_FIXED_PITCH) != 0) { 
                        IntNativeMethods.SIZE size = new IntNativeMethods.SIZE(); 
                        IntUnsafeNativeMethods.GetTextExtentPoint32(hdc, fontMeasureString, size);
                        // Note: intentional integer round off here for Win32 compat 
                        //retval.Width = (float)(((size.cx / 26) + 1) / 2);
                        retval.Width = (int)Math.Round(((float)size.cx) / ((float)fontMeasureString.Length));
                    }
                    else { 
                        retval.Width = tm.tmAveCharWidth;
                    } 
                } 
                finally {
                    SafeNativeMethods.SelectObject(hdc, hfontOld); 
                }
            }
            finally {
                UnsafeNativeMethods.DeleteCompatibleDC(hdc); 
            }
 
            return retval; 
        }
 
        /// 
        ///     This method is called when one of the auto scale properties changes, indicating
        ///     that we should scale controls on the next layout.
        ///  
        private void LayoutScalingNeeded() {
 
            EnableRequiredScaling(this, true); 
            state[stateScalingNeededOnLayout] = true;
 
            // If layout is not currently suspended, then perform a layout now,
            // as otherwise we don't know when one will happen.
            if (!IsLayoutSuspended) {
                LayoutTransaction.DoLayout(this, this, PropertyNames.Bounds); 
            }
        } 
 
        /// 
        ///     to maintain backwards compat with AutoScale on form, we need to keep the 
        ///     two models from conflicting.  This method is only here for Form to override
        ///     it and update its AutoScale property appropriately.
        /// 
        internal virtual void OnAutoScaleModeChanged() { 
        }
 
        ///  
        /// 
        ///    Raises the AutoValidateChanged event. 
        /// 
        protected virtual void OnAutoValidateChanged(EventArgs e) {
            if (autoValidateChanged != null) {
                autoValidateChanged(this, e); 
            }
        } 
 
        // Refer VsWhidbey : 515910 & 269769
        internal override void OnFrameWindowActivate(bool fActivate) { 
          if (fActivate) {
              IntSecurity.ModifyFocus.Assert();
              try {
                  if (ActiveControl == null) { 
                      SelectNextControl(null, true, true, true, false);
                  } 
                  InnerMostActiveContainerControl.FocusActiveControlInternal(); 
              }
              finally { 
                  CodeAccessPermission.RevertAssert();
              }
          }
      } 

        ///  
        ///  
        ///     Called when a child is about to resume its layout.  The default implementation
        ///     calls OnChildLayoutResuming on the parent. 
        /// 
        internal override void OnChildLayoutResuming(Control child, bool performLayout) {
            base.OnChildLayoutResuming(child, performLayout);
 
            // We need to scale children before their layout engines get to them.
            // We don't have a lot of opportunity for that because the code 
            // generator always generates a PerformLayout() right after a 
            // ResumeLayout(false).  This seems to be the most oppportune place
            // for thiis, although it is unfortunate. 
            if (!state[stateScalingChild] && !performLayout && AutoScaleMode != AutoScaleMode.None && AutoScaleMode != AutoScaleMode.Inherit && state[stateScalingNeededOnLayout]) {
                state[stateScalingChild] = true;
                try {
                    child.Scale(AutoScaleFactor, SizeF.Empty, this); 
                }
                finally { 
                    state[stateScalingChild] = false; 
                }
            } 
        }

        /// 
        ///  
        ///     Raises the CreateControl event.
        ///  
        protected override void OnCreateControl() { 
            base.OnCreateControl();
 
            if (Properties.GetObject(PropAxContainer) != null) {
                AxContainerFormCreated();
            }
            OnBindingContextChanged(EventArgs.Empty); 
        }
 
        ///  
        /// 
        ///    We override this to clear the current autoscale cache. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override void OnFontChanged(EventArgs e) {
            if (AutoScaleMode == AutoScaleMode.Font) { 
                currentAutoScaleDimensions = SizeF.Empty;
 
                // If the font changes and we are going to autoscale 
                // as a result, do it now, and wrap the entire
                // transaction in a suspend layout to prevent 
                // the layout engines from conflicting with our
                // work.
                SuspendAllLayout(this);
 
                try {
                    PerformAutoScale(!RequiredScalingEnabled, true); 
                } 
                finally {
                    ResumeAllLayout(this, false); 
                }
            }

            base.OnFontChanged(e); 
        }
 
        ///  
        ///     Container controls scale during layout.
        ///  
        protected override void OnLayout(LayoutEventArgs e) {
            PerformNeededAutoScaleOnLayout();
            base.OnLayout(e);
        } 

        ///  
        ///  
        ///     Called when the last resume layout call is made.  If performLayout is true
        ///     a layout will occur as soon as this call returns.  Layout is 
        ///     still suspended when this call is made.  The default implementation
        ///     calls OnChildLayoutResuming on the parent, if it exists.
        /// 
        internal override void OnLayoutResuming(bool performLayout) { 
            PerformNeededAutoScaleOnLayout();
            base.OnLayoutResuming(performLayout); 
        } 

        ///  
        /// 
        ///     Called when the parent changes.  Container controls prefer to have their parents
        ///     scale themselves, but when a parent is first changed, and as a result the font
        ///     changes as well, a container control should scale itself.  We save off this state 
        ///     so a later font change can trigger a scale of us.  We only set this state if
        ///     required scaling is disabled:  if it is enabled we are still initializing and 
        ///     parent changes are normal. 
        /// 
        protected override void OnParentChanged(EventArgs e) { 
            state[stateParentChanged] = !RequiredScalingEnabled;
            base.OnParentChanged(e);
        }
 
        /// 
        ///  
        ///     Performs scaling of this control.  Scaling works by scaling all children of this control. 
        ///     Those children that are ContainerControls will have their PerformAutoScale method called
        ///     so they can scale their children. 
        /// 
        public void PerformAutoScale() {
            PerformAutoScale(true, true);
        } 

        ///  
        ///  
        ///     Performs scaling of this control.  Scaling works by scaling all children of this control.
        /// 
        ///     If includedBounds is true those controls whose bounds have changed since
        ///     they were last scaled will be auto scaled.  If excludedBounds is true those
        ///     controls whose bounds have not changed since they were last scaled will be
        ///     auto scaled. 
        ///
        ///     PerformAutoScale is automatically called during OnLayout.  The parameters to 
        ///     PerformAutoScale are passed as follows: 
        ///
        ///     1.  If AutoScaleDimensions are set, includedBounds is set to true. 
        ///     2.  If a font change occurred, excludedBounds is set to true.
        /// 
        private void PerformAutoScale(bool includedBounds, bool excludedBounds) {
 
            bool suspended = false;
 
            try { 
                if (AutoScaleMode != AutoScaleMode.None && AutoScaleMode != AutoScaleMode.Inherit) {
                    SuspendAllLayout(this); 
                    suspended = true;

                    // Walk each control recursively and scale.  We search the control
                    // for its own set of scaling data; if we don't find it, we use the current 
                    // container control's scaling data.  Once we scale a control, we set
                    // its scaling factors to unity.  As we walk out of a container control, 
                    // we set its scaling factor to unity too. 
                    SizeF included = SizeF.Empty;
                    SizeF excluded = SizeF.Empty; 

                    if (includedBounds) included = AutoScaleFactor;
                    if (excludedBounds) excluded = AutoScaleFactor;
 
                    Scale(included, excluded, this);
                    autoScaleDimensions = CurrentAutoScaleDimensions; 
                } 
            }
            finally { 
                if (includedBounds) {
                    state[stateScalingNeededOnLayout] = false;
                    EnableRequiredScaling(this, false);
                } 
                state[stateParentChanged] = false;
 
                if (suspended) { 
                    ResumeAllLayout(this, false);
                } 
            }
        }

        ///  
        ///     Checks to see if we need to perform an autoscale in
        ///     response to a layout. 
        ///  
        private void PerformNeededAutoScaleOnLayout() {
            if (state[stateScalingNeededOnLayout]) { 
                PerformAutoScale(state[stateScalingNeededOnLayout], false);
            }
        }
 
        /// 
        ///     Recursively resumes all layout. 
        ///  
        internal void ResumeAllLayout(Control start, bool performLayout) {
 
            ControlCollection controlsCollection = start.Controls;
            // This may have changed the sizes of our children.
            // PERFNOTE: This is more efficient than using Foreach.  Foreach
            // forces the creation of an array subset enum each time we 
            // enumerate
            for(int i = 0; i < controlsCollection.Count; i++) { 
                ResumeAllLayout(controlsCollection[i], performLayout); 
            }
 
            start.ResumeLayout(performLayout);
        }

        ///  
        ///     Recursively suspends all layout.
        ///  
        internal void SuspendAllLayout(Control start) { 
            start.SuspendLayout();
            CommonProperties.xClearPreferredSizeCache(start); 

            ControlCollection controlsCollection = start.Controls;
            // This may have changed the sizes of our children.
            // PERFNOTE: This is more efficient than using Foreach.  Foreach 
            // forces the creation of an array subset enum each time we
            // enumerate 
            for(int i = 0; i < controlsCollection.Count; i++) { 
                SuspendAllLayout(controlsCollection[i]);
            } 
        }

        /// 
        ///  
        ///     Overrides the default scaling mechanism to account for autoscaling.  This
        ///     override behaves as follows:  any unchanged controls are always scaled 
        ///     according to the container control's AutoScaleFactor.  Any changed controls are 
        ///     scaled according to the provided scaling factor.
        ///  
        internal override void Scale(SizeF includedFactor, SizeF excludedFactor, Control requestingControl) {

            // If we're inhieriting our scaling from our parent, Scale is really easy:  just do the
            // base class implementation. 
            if (AutoScaleMode == AutoScaleMode.Inherit) {
                base.Scale(includedFactor, excludedFactor, requestingControl); 
            } 
            else {
                // We scale our controls based on our own auto scaling 
                // factor, not the one provided to us.  We only do this for
                // controls that are not required to be scaled (excluded controls).
                SizeF ourExcludedFactor = excludedFactor;
                SizeF childIncludedFactor = includedFactor; 

                if (!ourExcludedFactor.IsEmpty) { 
                    ourExcludedFactor = AutoScaleFactor; 
                }
 
                // If we're not supposed to be scaling, don't scale the internal
                // ones either.
                if (AutoScaleMode == AutoScaleMode.None) {
                    childIncludedFactor = AutoScaleFactor; 
                }
 
                // When we scale, we are establishing new baselines for the 
                // positions of all controls.  Therefore, we should resume(false).
                using (new LayoutTransaction(this, this, PropertyNames.Bounds, false)) { 

                    // Our own container control poses a problem.  We want
                    // an outer control to be responsible for scaling it,
                    // because the outer control knows the container's dimensions. 
                    // We detect this by checking who is requesting that the
                    // scaling occur. 
                    SizeF ourExternalContainerFactor = ourExcludedFactor; 

                    if (!excludedFactor.IsEmpty && ParentInternal != null) { 
                        ourExternalContainerFactor = SizeF.Empty;

                        bool scaleUs = (requestingControl != this || state[stateParentChanged]);
 
                        // Hack for design time support:  we may be parented within another form
                        // that is not part of the designer. 
                        if (!scaleUs) { 
                            bool dt = false;
                            bool parentDt = false; 
                            ISite site = Site;
                            ISite parentSite = ParentInternal.Site;

                            if (site != null) dt = site.DesignMode; 
                            if (parentSite != null) parentDt = parentSite.DesignMode;
 
                            if (dt && !parentDt) { 
                                scaleUs = true;
                            } 
                        }

                        if (scaleUs) {
                            ourExternalContainerFactor = excludedFactor; 
                        }
                    } 
 
                    ScaleControl(includedFactor, ourExternalContainerFactor, requestingControl);
                    ScaleChildControls(childIncludedFactor, ourExcludedFactor, requestingControl); 
                }
            }
        }
 
        /// 
        ///     Process an arrowKey press by selecting the next control in the group 
        ///     that the activeControl belongs to. 
        /// 
        ///  
        private bool ProcessArrowKey(bool forward) {
            Control group = this;
            if (activeControl != null) {
                group = activeControl.ParentInternal; 
            }
            return group.SelectNextControl(activeControl, forward, false, false, true); 
        } 

        ///  
        /// 
        /// 
        ///    Processes a dialog character. Overrides Control.processDialogChar().
        ///    This method calls the processMnemonic() method to check if the character 
        ///    is a mnemonic for one of the controls on the form. If processMnemonic()
        ///    does not consume the character, then base.processDialogChar() is 
        ///    called. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        protected override bool ProcessDialogChar(char charCode) {
#if DEBUG
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "ContainerControl.ProcessDialogChar [" + charCode.ToString() + "]"); 
#endif
            // If we're the top-level form or control, we need to do the mnemonic handling 
            // 
            ContainerControl parent = GetContainerControlInternal() as ContainerControl;
            if (parent != null && charCode != ' ' && ProcessMnemonic(charCode)) return true; 
            return base.ProcessDialogChar(charCode);
        }

        ///  
        /// 
        ///  
        ///    Processes a dialog key. Overrides Control.processDialogKey(). This 
        ///    method implements handling of the TAB, LEFT, RIGHT, UP, and DOWN
        ///    keys in dialogs. 
        ///    The method performs no processing on keys that include the ALT or
        ///    CONTROL modifiers. For the TAB key, the method selects the next control
        ///    on the form. For the arrow keys,
        ///    !!! 
        /// 
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)] 
        protected override bool ProcessDialogKey(Keys keyData) { 
#if DEBUG
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "ContainerControl.ProcessDialogKey [" + keyData.ToString() + "]"); 
#endif
            if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) {
                Keys keyCode = (Keys)keyData & Keys.KeyCode;
                switch (keyCode) { 
                    case Keys.Tab:
                        if (ProcessTabKey((keyData & Keys.Shift) == Keys.None)) return true; 
                        break; 
                    case Keys.Left:
                    case Keys.Right: 
                    case Keys.Up:
                    case Keys.Down:
                        if (ProcessArrowKey(keyCode == Keys.Right ||
                                            keyCode == Keys.Down)) return true; 
                        break;
                } 
            } 
            return base.ProcessDialogKey(keyData);
        } 


         /// 
         ///  
         [
             SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode) 
         ] 
         protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "ContainerControl.ProcessCmdKey " + msg.ToString()); 

            if (base.ProcessCmdKey(ref msg, keyData)) {
            return true;
            } 
            if (ParentInternal == null) {
                // unfortunately, we have to stick this here for the case where we're hosted without 
                // a form in the chain.  This would be something like a context menu strip with shortcuts 
                // hosted within Office, VS or IE.
                // 
                // this is an optimized search O(number of ToolStrips in thread)
                // that happens only if the key routing makes it to the top.
                return ToolStripManager.ProcessCmdKey(ref msg, keyData);
            } 
            return false;
        } 
 
        /// 
        ///  
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        protected internal override bool ProcessMnemonic(char charCode) {
#if DEBUG
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "ContainerControl.ProcessMnemonic [" + charCode.ToString() + "]"); 
            Debug.Indent();
            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "this == " + ToString()); 
#endif 
            if( !CanProcessMnemonic() ){
                return false; 
            }

            if (Controls.Count == 0) {
                Debug.Unindent(); 
                return false;
            } 
 
            // Start with the active control.
            // 
            Control start = ActiveControl;

#if DEBUG
            int count = 0; 
#endif //DEBUG
 
            // Set the processing mnemonic flag so child controls don't check for it when checking if they 
            // can process the mnemonic.
            this.state[stateProcessingMnemonic] = true; 

            bool processed = false;

            try { 
                // safety flag to avoid infinite loop when testing controls in a container.
                bool wrapped = false; 
 
                Control ctl = start;
                Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "Check starting at '" + ((start != null) ? start.ToString() : "") + "'"); 

                do  {
                    // Loop through the controls starting at the control next to the current Active control in the Tab order
                    // till we find someone willing to process this mnemonic. 
                    // We don't start the search on the Active control to allow controls in the same container with the same
                    // mnemonic (bad UI design but supported) to be processed sequentially (see VSWhidbey#428029). 
#if DEBUG 
                count++;
                if (count > 9999) { 
                    Debug.Fail("Infinite loop trying to find controls which can ProcessMnemonic()!!!");
                }
#endif //DEBUG
                    ctl = GetNextControl(ctl, true); 

                    if ( ctl != null ) { 
#if DEBUG 
                        Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "  ...checking for mnemonics on " + ctl.ToString());
                        // Control.TraceMnemonicProcessing.Enabled disables CanProcessMnemonic consistency check. 
                        bool canProcess = Control.TraceMnemonicProcessing.Enabled ? true : ctl.CanProcessMnemonic(); // Processing the mnemonic can change the value of CanProcessMnemonic. See ASURT 39583.
#endif
                        // Processing the mnemonic can change the value of CanProcessMnemonic. See ASURT 39583.
                        if (ctl.ProcessMnemonic(charCode)) { 
#if DEBUG
                            Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "  ...mnemonics found"); 
                            Debug.Assert((Control.TraceMnemonicProcessing.Enabled || canProcess), "ProcessMnemonic returned true, even though CanProcessMnemonic() is false.  Someone probably overrode ProcessMnemonic and forgot to test CanSelect or CanProcessMnemonic()."); 
                            Debug.Unindent();
#endif 
                            processed = true;
                            break;
                        }
                    } 
                    else { // ctl is null
                        if( wrapped ){ 
                            break;      // This avoids infinite loops 
                        }
 
                        wrapped = true;
                    }
                } while (ctl != start);
            } 
            finally {
                this.state[stateProcessingMnemonic] = false; 
            } 

            Debug.Unindent(); 
            return processed;
        }

        ///  
        /// 
        ///    Selects the next available control and makes it the active control. 
        ///  
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        protected virtual bool ProcessTabKey(bool forward) { 
            if (SelectNextControl(activeControl, forward, true, true, false)) return true;
            return false;
        }
 
        private ScrollableControl FindScrollableParent(Control ctl) {
            Control current = ctl.ParentInternal; 
            while (current != null && !(current is ScrollableControl)) { 
                current = current.ParentInternal;
            } 
            if (current != null) {
                return(ScrollableControl)current;
            }
            return null; 
        }
 
        private void ScrollActiveControlIntoView() { 
            Control last = activeControl;
            if (last != null) { 
                ScrollableControl scrollParent = FindScrollableParent(last);

                while (scrollParent != null) {
                    scrollParent.ScrollControlIntoView(activeControl); 
                    last = scrollParent;
                    scrollParent = FindScrollableParent(scrollParent); 
                } 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        protected override void Select(bool directed, bool forward) { 
            bool correctParentActiveControl = true; 
            if (ParentInternal != null)
            { 
                IContainerControl c = ParentInternal.GetContainerControlInternal();
                if (c != null)
                {
                    c.ActiveControl = this; 
                    correctParentActiveControl = (c.ActiveControl == this);
                } 
            } 
            if (directed && correctParentActiveControl)
            { 
                SelectNextControl(null, forward, true, true, false);
            }
        }
 
        /// 
        ///     Implements ActiveControl property setter. 
        ///  
        private void SetActiveControl(Control ctl) {
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::SetActiveControl(" + (ctl == null ? "null" : ctl.Name) + ") - " + this.Name); 
            Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ModifyFocus Demanded");
            IntSecurity.ModifyFocus.Demand();

            SetActiveControlInternal(ctl); 
        }
 
        ///  
        ///     Unsafe version of SetActiveControl - Use with caution!
        ///  
        internal void SetActiveControlInternal(Control value) {
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::SetActiveControlInternal(" + (value == null ? "null" : value.Name) + ") - " + this.Name);
            if (activeControl != value || (value != null && !value.Focused)) {
                if (value != null && !Contains(value)) { 
                    throw new ArgumentException(SR.GetString(SR.CannotActivateControl));
                } 
 
                bool ret;
                ContainerControl cc = this; 

                if (value != null && value.ParentInternal != null)
                {
                    cc = (value.ParentInternal.GetContainerControlInternal()) as ContainerControl; 
                }
                if (cc != null) 
                { 
                    // Call to the recursive function that corrects the chain
                    // of active controls 
                    ret = cc.ActivateControlInternal(value, false);
                }
                else
                { 
                    ret = AssignActiveControlInternal(value);
                } 
 
                if (cc != null && ret)
                { 
                    ContainerControl ccAncestor = this;
                    while (ccAncestor.ParentInternal != null &&
                           ccAncestor.ParentInternal.GetContainerControlInternal() is ContainerControl)
                    { 
                        ccAncestor = ccAncestor.ParentInternal.GetContainerControlInternal() as ContainerControl;
                        Debug.Assert(ccAncestor != null); 
                    } 

                    if (ccAncestor.ContainsFocus && 
                        (value == null ||
                         !(value is UserControl) ||
                         (value is UserControl && !((UserControl)value).HasFocusableChild())))
                    { 
                        cc.FocusActiveControlInternal();
                    } 
                } 
            }
        } 

        internal ContainerControl InnerMostActiveContainerControl
        {
            get 
            {
                ContainerControl ret = this; 
                while (ret.ActiveControl is ContainerControl) 
                {
                    ret = (ContainerControl) ret.ActiveControl; 
                }
                return ret;
            }
        } 

        internal ContainerControl InnerMostFocusedContainerControl 
        { 
            get
            { 
                ContainerControl ret = this;
                while (ret.focusedControl is ContainerControl)
                {
                    ret = (ContainerControl) ret.focusedControl; 
                }
                return ret; 
            } 
        }
 
        /// 
        /// 
        ///     Updates the default button based on current selection, and the
        ///     acceptButton property. 
        /// 
        ///  
        protected virtual void UpdateDefaultButton() { 
            // hook for form
        } 

        /// 
        ///     Updates the focusedControl variable by walking towards the
        ///     activeControl variable, firing enter and leave events and validation 
        ///     as necessary.
        ///  
        ///  
        internal void UpdateFocusedControl() {
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::UpdateFocusedControl() - " + this.Name); 

            // Capture the current focusedControl as the unvalidatedControl if we don't have one/are not validating.
            EnsureUnvalidatedControl(focusedControl);
            Control pathControl = focusedControl; 

            while (activeControl != pathControl) { 
                if (pathControl == null || pathControl.IsDescendant(activeControl)) { 
                    // heading down. find next control on path.
                    Control nextControlDown = activeControl; 
                    while (true) {
                        Control parent = nextControlDown.ParentInternal;
                        if (parent == this || parent == pathControl)
                            break; 
                        nextControlDown = nextControlDown.ParentInternal;
                    } 
 
                    Control priorFocusedControl = focusedControl = pathControl;
                    EnterValidation(nextControlDown); 
                    // If validation changed position, then jump back to the loop.
                    if (focusedControl != priorFocusedControl) {
                        pathControl = focusedControl;
                        continue; 
                    }
 
                    pathControl = nextControlDown; 
                    if (NativeWindow.WndProcShouldBeDebuggable) {
                        pathControl.NotifyEnter(); 
                    }
                    else {
                        try {
                            pathControl.NotifyEnter(); 
                        }
                        catch (Exception e) { 
                            Application.OnThreadException(e); 
                        }
                    } 
                }
                else {
                    // heading up.
                    ContainerControl innerMostFCC = InnerMostFocusedContainerControl; 
                    Control stopControl = null;
 
                    if (innerMostFCC.focusedControl != null) 
                    {
                        pathControl = innerMostFCC.focusedControl; 
                        stopControl = innerMostFCC;

                        if (innerMostFCC != this)
                        { 
                            innerMostFCC.focusedControl = null;
                            if (!(innerMostFCC.ParentInternal != null && innerMostFCC.ParentInternal is MdiClient)) 
                            { 
                                // Don't reset the active control of a MDIChild that loses the focus
                                innerMostFCC.activeControl = null; 
                            }
                        }
                    }
                    else 
                    {
                        pathControl = innerMostFCC; 
                        // innerMostFCC.ParentInternal can be null when the ActiveControl is deleted. 
                        if (innerMostFCC.ParentInternal != null)
                        { 
                            ContainerControl cc = (innerMostFCC.ParentInternal.GetContainerControlInternal()) as ContainerControl;
                            stopControl = cc;
                            if (cc != null && cc != this)
                            { 
                                cc.focusedControl = null;
                                cc.activeControl = null; 
                            } 
                        }
                    } 

                    do
                    {
                        Control leaveControl = pathControl; 

                        if (pathControl != null) 
                        { 
                            pathControl = pathControl.ParentInternal;
                        } 

                        if (pathControl == this)
                        {
                            pathControl = null; 
                        }
 
                        if (leaveControl != null) 
                        {
                            if (NativeWindow.WndProcShouldBeDebuggable) { 
                                leaveControl.NotifyLeave();
                            }
                            else {
                                try { 
                                    leaveControl.NotifyLeave();
                                } 
                                catch (Exception e) { 
                                    Application.OnThreadException(e);
                                } 
                            }
                        }
                    }
                    while (pathControl != null && 
                           pathControl != stopControl &&
                           !pathControl.IsDescendant(activeControl)); 
                } 
            }
 
#if DEBUG
            if (activeControl == null || (activeControl != null && activeControl.ParentInternal != null && !activeControl.ParentInternal.IsContainerControl))
            {
                Debug.Assert(activeControl == null || activeControl.ParentInternal.GetContainerControlInternal() == this); 
            }
#endif 
            focusedControl = activeControl; 
            if (activeControl != null) {
                EnterValidation(activeControl); 
            }
        }

        ///  
        ///     Make sure we have a valid choice of last unvalidated control if at all possible.
        ///  
        ///  
        private void EnsureUnvalidatedControl(Control candidate) {
            // Don't change the unvalidated control while in the middle of validation (re-entrancy) 
            if (state[stateValidating]) {
                return;
            }
 
            // Don't change the existing unvalidated control
            if (unvalidatedControl != null) { 
                return; 
            }
 
            // No new choice of unvalidated control was specified - leave unvalidated control blank
            if (candidate == null) {
                return;
            } 

            // Specified control has auto-validation disabled - leave unvalidated control blank 
            if (!candidate.ShouldAutoValidate) { 
                return;
            } 

            // Go ahead and make specified control the current unvalidated control for this container
            unvalidatedControl = candidate;
 
            // In the case of nested container controls, try to pick the deepest possible unvalidated
            // control. For a container with no unvalidated control, use the active control instead. 
            // Stop as soon as we encounter any control that has auto-validation turned off. 
            while (unvalidatedControl is ContainerControl) {
                ContainerControl container = unvalidatedControl as ContainerControl; 

                if (container.unvalidatedControl != null && container.unvalidatedControl.ShouldAutoValidate) {
                    unvalidatedControl = container.unvalidatedControl;
                } 
                else if (container.activeControl != null && container.activeControl.ShouldAutoValidate) {
                    unvalidatedControl = container.activeControl; 
                } 
                else {
                    break; 
                }
            }
        }
 
        /// 
        ///     Validates the last unvalidated control and its ancestors (up through the ancestor in common 
        ///     with enterControl) if enterControl causes validation. 
        /// 
        ///  
        private void EnterValidation(Control enterControl) {
            // No unvalidated control to validate - stop now
            if (unvalidatedControl == null) {
                return; 
            }
 
            // Entered control does not trigger validation - stop now 
            if (!enterControl.CausesValidation) {
                return; 
            }

            // Get the effective AutoValidate mode for this control (based on its container control)
            AutoValidate autoValidateMode = Control.GetAutoValidateForControl(unvalidatedControl); 

            // Auto-validate has been turned off in container of unvalidated control - stop now 
            if (autoValidateMode == AutoValidate.Disable) { 
                return;
            } 

            // Find common ancestor of entered control and unvalidated control
            Control commonAncestor = enterControl;
            while (commonAncestor != null && !commonAncestor.IsDescendant(unvalidatedControl)) { 
                commonAncestor = commonAncestor.ParentInternal;
            } 
 
            // Should we force focus to stay on same control if there is a validation error?
            bool preventFocusChangeOnError = (autoValidateMode == AutoValidate.EnablePreventFocusChange); 

            // Validate control and its ancestors, up to (but not including) the common ancestor
            ValidateThroughAncestor(commonAncestor, preventFocusChangeOnError);
        } 

        ///  
        ///  
        ///     
        ///     Validates the last unvalidated control and its ancestors up through, but not including the current control. 
        ///
        ///     This version always performs validation, regardless of the AutoValidate setting of the control's parent.
        ///     
        ///  
        //
        // ------------------------------- 
        // INTERNAL NOTE FOR [....] DEVS: This version is intended for user code that wants to force validation, even 
        // while auto-validation is turned off. When adding any explicit Validate() calls to our code, consider using
        // Validate(true) rather than Validate(), so that you will be sensitive to the current auto-validation setting. 
        // -------------------------------
        //
        public bool Validate() {
            return Validate(false); 
        }
 
        ///  
        /// 
        ///      
        ///     Validates the last unvalidated control and its ancestors up through, but not including the current control.
        ///
        ///     This version will skip validation if checkAutoValidate is true and the effective AutoValidate setting, as
        ///     determined by the control's parent, is AutoValidate.Disable. 
        ///     
        ///  
        public bool Validate(bool checkAutoValidate) { 
            bool validatedControlAllowsFocusChange;
            return ValidateInternal(checkAutoValidate, out validatedControlAllowsFocusChange); 
        }

        internal bool ValidateInternal(bool checkAutoValidate, out bool validatedControlAllowsFocusChange) {
            validatedControlAllowsFocusChange = false; 

            if (this.AutoValidate == AutoValidate.EnablePreventFocusChange || 
                (activeControl != null && activeControl.CausesValidation)) { 
                if (unvalidatedControl == null) {
                    if (focusedControl is ContainerControl && focusedControl.CausesValidation) { 
                        ContainerControl c = (ContainerControl)focusedControl;
                        if( !c.ValidateInternal(checkAutoValidate, out validatedControlAllowsFocusChange) ){
                            return false;
                        } 
                    }
                    else { 
                        unvalidatedControl = focusedControl; 
                    }
                } 

                // Should we force focus to stay on same control if there is a validation error?
                bool preventFocusChangeOnError = true;
 
                Control controlToValidate = unvalidatedControl != null ? unvalidatedControl : focusedControl;
 
                if (controlToValidate != null) 
                {
                    // Get the effective AutoValidate mode for unvalidated control (based on its container control) 
                    AutoValidate autoValidateMode = Control.GetAutoValidateForControl(controlToValidate);

                    // Auto-validate has been turned off in container of unvalidated control - stop now
                    if (checkAutoValidate && autoValidateMode == AutoValidate.Disable) 
                    {
                        return true; 
                    } 
                    preventFocusChangeOnError = (autoValidateMode == AutoValidate.EnablePreventFocusChange);
                    validatedControlAllowsFocusChange = (autoValidateMode == AutoValidate.EnableAllowFocusChange); 
                }

                return ValidateThroughAncestor(null, preventFocusChangeOnError);
            } 
            return true;
        } 
 
        /// 
        ///  
        ///     Validates all selectable child controls in the container, including descendants. This is
        ///     equivalent to calling ValidateChildren(ValidationConstraints.Selectable). See 
        ///     for details of exactly which child controls will be validated.
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public virtual bool ValidateChildren() { 
            return ValidateChildren(ValidationConstraints.Selectable); 
        }
 
        /// 
        /// 
        ///     Validates all the child controls in the container. Exactly which controls are
        ///     validated and which controls are skipped is determined by . 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public virtual bool ValidateChildren(ValidationConstraints validationConstraints) { 
            // validationConstraints must be a combination of
            // None = 0x00, Selectable = 0x01, Enabled = 0x02, Visible = 0x04, TabStop = 0x08, ImmediateChildren = 0x10 
            // Not using ClientUtils.IsValidEnum here because this is a flags enum and everything is valid between 0x00 and 0x1F.
            if ((int)validationConstraints < 0x00 || (int)validationConstraints > 0x1F)
            {
                throw new InvalidEnumArgumentException("validationConstraints", (int)validationConstraints, typeof(ValidationConstraints)); 
            }
            return !PerformContainerValidation(validationConstraints); 
        } 

        private bool ValidateThroughAncestor(Control ancestorControl, bool preventFocusChangeOnError) { 
            if (ancestorControl == null)
                ancestorControl = this;
            if (state[stateValidating])
                return false; 
            if (unvalidatedControl == null)
                unvalidatedControl = focusedControl; 
            //return true for a Container Control with no controls to validate.... 
            //
            if (unvalidatedControl == null) 
                return true;
            if (!ancestorControl.IsDescendant(unvalidatedControl))
                return false;
 
            this.state[stateValidating] = true;
            bool cancel = false; 
 
            Control currentActiveControl = activeControl;
            Control currentValidatingControl = unvalidatedControl; 
            if (currentActiveControl != null) {
                currentActiveControl.ValidationCancelled = false;
                if (currentActiveControl is ContainerControl) {
                    ContainerControl currentActiveContainerControl = currentActiveControl as ContainerControl; 

                    currentActiveContainerControl.ResetValidationFlag(); 
                } 
            }
            try { 
                while (currentValidatingControl != null && currentValidatingControl != ancestorControl) {
                    try {
                        cancel = currentValidatingControl.PerformControlValidation(false);
                    } 
                    catch {
                        cancel = true; 
                        throw; 
                    }
 
                    if (cancel) {
                        break;
                    }
 
                    currentValidatingControl = currentValidatingControl.ParentInternal;
                } 
 
                if (cancel && preventFocusChangeOnError) {
                    if (unvalidatedControl == null && currentValidatingControl != null && 
                        ancestorControl.IsDescendant(currentValidatingControl))
                    {
                        unvalidatedControl = currentValidatingControl;
                    } 
                    // This bit 'marks' the control that was going to get the focus, so that it will ignore any pending
                    // mouse or key events. Otherwise it would still perform its default 'click' action or whatever. 
                    if (currentActiveControl == activeControl) { 
                        if (currentActiveControl != null) {
                            CancelEventArgs ev = new CancelEventArgs(); 
                            ev.Cancel = true;
                            currentActiveControl.NotifyValidationResult(currentValidatingControl, ev);
                            if (currentActiveControl is ContainerControl) {
                                ContainerControl currentActiveContainerControl = currentActiveControl as ContainerControl; 
                                if (currentActiveContainerControl.focusedControl != null) {
                                    currentActiveContainerControl.focusedControl.ValidationCancelled = true; 
                                } 
                                currentActiveContainerControl.ResetActiveAndFocusedControlsRecursive();
                            } 
                        }
                    }
                    // This bit forces the focus to move back to the invalid control
                    SetActiveControlInternal(unvalidatedControl); 
                }
            } 
            finally { 
                unvalidatedControl = null;
                state[stateValidating] = false; 
            }

            return !cancel;
        } 

        private void ResetValidationFlag()  { 
            // PERFNOTE: This is more efficient than using Foreach.  Foreach 
            // forces the creation of an array subset enum each time we
            // enumerate 
            Control.ControlCollection children = this.Controls;
            int count = children.Count;
            for(int i = 0; i < count; i++) {
                children[i].ValidationCancelled = false; 
            }
        } 
 
        internal void ResetActiveAndFocusedControlsRecursive()
        { 
            if (activeControl is ContainerControl)
            {
                ((ContainerControl) activeControl).ResetActiveAndFocusedControlsRecursive();
            } 
            activeControl = null;
            focusedControl = null; 
        } 

        [EditorBrowsable(EditorBrowsableState.Never)] 
        internal virtual bool ShouldSerializeAutoValidate() {
            return autoValidate != AutoValidate.Inherit;
        }
 
        /// 
        ///     WM_SETFOCUS handler 
        ///  
        /// 
        private void WmSetFocus(ref Message m) { 
            Debug.WriteLineIf(Control.FocusTracing.TraceVerbose, "ContainerControl::WmSetFocus() - " + this.Name);
            if (!HostedInWin32DialogManager) {
                if (ActiveControl != null) {
                    WmImeSetFocus(); 
                    // [....]: Do not raise GotFocus event since the focus
                    //         is given to the visible ActiveControl 
                    if (!ActiveControl.Visible) { 
                        OnGotFocus(EventArgs.Empty);
                    } 
                    FocusActiveControlInternal();
                }
                else {
                    if (ParentInternal != null) { 
                        IContainerControl c = ParentInternal.GetContainerControlInternal();
                        if (c != null) { 
                            bool succeeded = false; 

                            ContainerControl knowncontainer = c as ContainerControl; 
                            if (knowncontainer != null) {
                                succeeded = knowncontainer.ActivateControlInternal(this);
                            }
                            else { 

                                // SECREVIEW : Taking focus and activating a control in response 
                                //           : to a user gesture (WM_SETFOCUS) is OK. 
                                //
                                IntSecurity.ModifyFocus.Assert(); 
                                try {
                                    succeeded = c.ActivateControl(this);
                                }
                                finally { 
                                    CodeAccessPermission.RevertAssert();
                                } 
                            } 
                            if (!succeeded) {
                                return; 
                            }
                        }
                    }
                    base.WndProc(ref m); 
                }
            } 
            else { 
                base.WndProc(ref m);
            } 
        }

        /// 
        ///  
        /// 
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) { 
            switch (m.Msg) {
                case NativeMethods.WM_SETFOCUS:
                    WmSetFocus(ref m);
                    break; 
                default:
                    base.WndProc(ref m); 
                    break; 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK