DockAndAnchorLayout.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / WinForms / Managed / System / WinForms / Layout / DockAndAnchorLayout.cs / 1 / DockAndAnchorLayout.cs

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

namespace System.Windows.Forms.Layout { 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing; 

    using ControlCollection = System.Windows.Forms.Control.ControlCollection; 
    using CompModSwitches = System.ComponentModel.CompModSwitches; 

    internal class DefaultLayout : LayoutEngine { 

        // Singleton instance shared by all controls.
        internal static readonly DefaultLayout Instance = new DefaultLayout();
 
        private static readonly int _layoutInfoProperty = PropertyStore.CreateKey();
        private static readonly int _cachedBoundsProperty = PropertyStore.CreateKey(); 
 
        // Loop through the AutoSized controls and expand them if they are smaller than
        // their preferred size.  If expanding the controls causes overlap, bump the overlapped 
        // control if it is AutoRelocatable.
        private static void LayoutAutoSizedControls(IArrangedElement container) {
            ArrangedElementCollection children = container.Children;
            for (int i = children.Count - 1; i >= 0; i--) { 
                IArrangedElement element = children[i];
 
                if(CommonProperties.xGetAutoSizedAndAnchored(element)) { 
                    Rectangle bounds = GetCachedBounds(element);
 
                    AnchorStyles anchor = GetAnchor(element);
                    Size proposedConstraints = LayoutUtils.MaxSize;

                    if ((anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right)) { 
                        proposedConstraints.Width = bounds.Width;
                    } 
                    if ((anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) { 
                        proposedConstraints.Height = bounds.Height;
                    } 
                    Size prefSize = element.GetPreferredSize(proposedConstraints);

                    Rectangle newBounds = bounds;
 
                    if (CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink) {
                        // this is the case for simple things like radio button, checkbox, etc. 
                        newBounds = GetGrowthBounds(element, prefSize); 
                    }
                    else { 
                        // we had whacked this check, but it turns out it causes undesirable
                        // behavior in things like panel.  a panel with no elements sizes to 0,0.
                        if(bounds.Width < prefSize.Width || bounds.Height < prefSize.Height) {
                            Size newSize = LayoutUtils.UnionSizes(bounds.Size, prefSize); 
                            newBounds = GetGrowthBounds(element, newSize);
                        } 
                    } 
                    if (newBounds != bounds) {
                         SetCachedBounds(element, newBounds); 
                    }
                }
            }
        } 

        // Gets the bounds of the element after growing to newSize (note that depending on 
        // anchoring the element may grow to the left/updwards rather than to the 
        // right/downwards. i.e., it may be translated.)
        private static Rectangle GetGrowthBounds(IArrangedElement element, Size newSize) { 
            GrowthDirection direction = GetGrowthDirection(element);
            Rectangle oldBounds = GetCachedBounds(element);
            Point location = oldBounds.Location;
 
            Debug.Assert((CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink || newSize.Height >= oldBounds.Height && newSize.Width >= oldBounds.Width),
                "newSize expected to be >= current size."); 
 
            if((direction & GrowthDirection.Left) != GrowthDirection.None) {
                // We are growing towards the left, translate X 
                location.X -= newSize.Width - oldBounds.Width;
            }

            if((direction & GrowthDirection.Upward) != GrowthDirection.None) { 
                // We are growing towards the top, translate Y
                location.Y -= newSize.Height - oldBounds.Height; 
            } 

            Rectangle newBounds = new Rectangle(location, newSize); 

            Debug.Assert((CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink || newBounds.Contains(oldBounds)), "How did we resize in such a way we no longer contain our old bounds?");

            return newBounds; 
        }
        // Examines an elements anchoring to figure out which direction it should grow. 
        private static GrowthDirection GetGrowthDirection(IArrangedElement element) { 
            AnchorStyles anchor = GetAnchor(element);
            GrowthDirection growthDirection = GrowthDirection.None; 

            if((anchor & AnchorStyles.Right) != AnchorStyles.None
                && (anchor & AnchorStyles.Left) == AnchorStyles.None) {
                // element is anchored to the right, but not the left. 
                growthDirection |= GrowthDirection.Left;
            } else { 
                // otherwise we grow towards the right (common case) 
                growthDirection |= GrowthDirection.Right;
            } 

            if((anchor & AnchorStyles.Bottom) != AnchorStyles.None
                && (anchor & AnchorStyles.Top) == AnchorStyles.None) {
                // element is anchored to the bottom, but not the top. 
                growthDirection |= GrowthDirection.Upward;
            } else { 
                // otherwise we grow towards the bottom. (common case) 
                growthDirection |= GrowthDirection.Downward;
            } 

            Debug.Assert((growthDirection & GrowthDirection.Left) == GrowthDirection.None
                || (growthDirection & GrowthDirection.Right) == GrowthDirection.None,
                "We shouldn't allow growth to both the left and right."); 
            Debug.Assert((growthDirection & GrowthDirection.Upward) == GrowthDirection.None
                || (growthDirection & GrowthDirection.Downward) == GrowthDirection.None, 
                "We shouldn't allow both upward and downward growth."); 
            return growthDirection;
        } 

        // Layout for a single anchored control.  There's no order dependency when laying out anchored controls.
        private static Rectangle GetAnchorDestination(IArrangedElement element, Rectangle displayRect, bool measureOnly) {
            // Container can not be null since we AschorControls takes a non-null container. 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t'" + element + "' is anchored at " + GetCachedBounds(element).ToString());
 
            AnchorInfo layout = GetAnchorInfo(element); 

            int left = layout.Left + displayRect.X; 
            int top = layout.Top + displayRect.Y;
            int right = layout.Right + displayRect.X;
            int bottom = layout.Bottom + displayRect.Y;
 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...anchor dim (l,t,r,b) {"
                              + (left) 
                              + ", " + (top) 
                              + ", " + (right)
                              + ", " + (bottom) 
                              + "}");

            AnchorStyles anchor = GetAnchor(element);
 
            if (IsAnchored(anchor, AnchorStyles.Right)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting right"); 
                right += displayRect.Width; 

                if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left");
                    left += displayRect.Width;
                }
            } 
            else if (!IsAnchored(anchor, AnchorStyles.Left)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left & right"); 
                right += (displayRect.Width / 2); 
                left += (displayRect.Width / 2);
            } 

            if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting bottom");
                bottom += displayRect.Height; 

                if (!IsAnchored(anchor, AnchorStyles.Top)) { 
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top"); 
                    top += displayRect.Height;
                } 
            }
            else if (!IsAnchored(anchor, AnchorStyles.Top)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top & bottom");
                bottom += (displayRect.Height/2); 
                top += (displayRect.Height/2);
            } 
 
            if (!measureOnly) {
                // the size is actually zero, set the width and heights appropriately. 
                if (right < left) right = left;
                if (bottom < top) bottom = top;
            }
            else { 
                Rectangle cachedBounds = GetCachedBounds(element);
                // in this scenario we've likely been passed a 0 sized display rectangle to determine our height. 
                // we will need to translate the right and bottom edges as necessary to the positive plane. 

                // right < left means the control is anchored both left and right. 
                // cachedBounds != element.Bounds means  the element's size has changed
                // any, all, or none of these can be true.
                if (right < left || cachedBounds.Width != element.Bounds.Width || cachedBounds.X != element.Bounds.X) {
                    if (cachedBounds != element.Bounds) { 
                        left = Math.Max(Math.Abs(left), Math.Abs(cachedBounds.Left));
                    } 
                    right = left + Math.Max(element.Bounds.Width, cachedBounds.Width) + Math.Abs(right); 
                }
                else { 
                    left = left > 0 ? left : element.Bounds.Left;
                    right = right > 0 ? right : element.Bounds.Right + Math.Abs(right);
                }
 
                // bottom < top means the control is anchored both top and bottom.
                // cachedBounds != element.Bounds means  the element's size has changed 
                // any, all, or none of these can be true. 
                if (bottom < top || cachedBounds.Height != element.Bounds.Height || cachedBounds.Y != element.Bounds.Y) {
                    if (cachedBounds != element.Bounds) { 
                        top = Math.Max(Math.Abs(top), Math.Abs(cachedBounds.Top));
                    }
                    bottom = top + Math.Max(element.Bounds.Height, cachedBounds.Height) + Math.Abs(bottom);
                } 
                else {
                    top = top > 0 ? top : element.Bounds.Top; 
                    bottom = bottom > 0 ? bottom : element.Bounds.Bottom + Math.Abs(bottom); 
                }
            } 

            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...new anchor dim (l,t,r,b) {"
                                                                      + (left)
                                                                      + ", " + (top) 
                                                                      + ", " + (right)
                                                                      + ", " + (bottom) 
                                                                      + "}"); 

            return new Rectangle(left, top, right - left, bottom - top); 
        }

        private static void LayoutAnchoredControls(IArrangedElement container) {
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tAnchor Processing"); 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\tdisplayRect: " + container.DisplayRectangle.ToString());
 
            Rectangle displayRectangle = container.DisplayRectangle; 
            if (CommonProperties.GetAutoSize(container) && ((displayRectangle.Width == 0) || (displayRectangle.Height == 0))) {
                // we havent set oursleves to the preferred size yet.  proceeding will 
                // just set all the control widths to zero.  let's return here
                return;
            }
 

            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) { 
                IArrangedElement element = children[i];
 
                if (CommonProperties.GetNeedsAnchorLayout(element)) {
                    Debug.Assert(GetAnchorInfo(element) != null, "AnchorInfo should be initialized before LayoutAnchorControls().");
                    SetCachedBounds(element, GetAnchorDestination(element, displayRectangle, /*measureOnly=*/false));
                } 
            }
        } 
 
        private static Size LayoutDockedControls(IArrangedElement container, bool measureOnly) {
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tDock Processing"); 
            Debug.Assert(!HasCachedBounds(container),
                "Do not call this method with an active cached bounds list.");

            // If measuring, we start with an empty rectangle and add as needed. 
            // If doing actual layout, we start with the container's rect and subtract as we layout.
            Rectangle remainingBounds = measureOnly ? Rectangle.Empty : container.DisplayRectangle; 
            Size preferredSize = Size.Empty; 

            IArrangedElement mdiClient = null; 

            // Docking layout is order dependent. After much debate, we decided to use z-order as the
            // docking order.  (Introducing a DockOrder property was a close second)
            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = children[i]; 
 
                Debug.Assert(element.Bounds == GetCachedBounds(element), "Why do we have cachedBounds for a docked element?");
 
                if (CommonProperties.GetNeedsDockLayout(element)) {
                     // VSWhidbey #109974: Some controls modify their bounds when you call SetBoundsCore.  We
                    // therefore need to read the value of bounds back when adjusting our layout rectangle.
                    switch (GetDock(element)) { 
                        case DockStyle.Top: {
                            Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly); 
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 

                            // What we are really doing here: top += element.Bounds.Height;
                            remainingBounds.Y += element.Bounds.Height;
                            remainingBounds.Height -= element.Bounds.Height; 
                            break;
                        } 
                        case DockStyle.Bottom: { 
                            Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Bottom - elementSize.Height, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds);

                            // What we are really doing here: bottom -= element.Bounds.Height; 
                            remainingBounds.Height -= element.Bounds.Height;
 
                            break; 
                        }
                        case DockStyle.Left: { 
                            Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height);

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 

                            // What we are really doing here: left += element.Bounds.Width; 
                            remainingBounds.X += element.Bounds.Width; 
                            remainingBounds.Width -= element.Bounds.Width;
                            break; 
                        }
                        case DockStyle.Right: {
                            Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.Right - elementSize.Width, remainingBounds.Y, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 
 
                            // What we are really doing here: right -= element.Bounds.Width;
                            remainingBounds.Width -= element.Bounds.Width; 
                            break;
                        }
                        case DockStyle.Fill:
                            if (element is MdiClient) { 
                                Debug.Assert(mdiClient == null, "How did we end up with multiple MdiClients?");
                                mdiClient = element; 
                            } 
                            else {
                                Size elementSize = remainingBounds.Size;//GetFillDockedSize(element, remainingBounds.Size, measureOnly); 
                                Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height);

                                xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds);
                            } 
                            break;
                        default: 
                            Debug.Fail("Unsupported value for dock."); 
                            break;
                    } 
                }

                // Treat the MDI client specially, since it's supposed to blend in with the parent form
                if (mdiClient != null) { 
                    SetCachedBounds(mdiClient, remainingBounds);
                } 
            } 
            return preferredSize;
        } 

        // Helper method that either sets the element bounds or does the preferredSize computation based on
        // the value of measureOnly.
        private static void xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, bool measureOnly, ref Size preferredSize, ref Rectangle remainingBounds) { 
            if (measureOnly) {
                Size neededSize = new Size( 
                    Math.Max(0, newElementBounds.Width - remainingBounds.Width), 
                    Math.Max(0, newElementBounds.Height - remainingBounds.Height));
 
                DockStyle dockStyle = GetDock(element);
                if ((dockStyle == DockStyle.Top) || (dockStyle == DockStyle.Bottom)) {
                    neededSize.Width = 0;
                } 
                if ((dockStyle == DockStyle.Left) || (dockStyle == DockStyle.Right)) {
                    neededSize.Height = 0; 
                } 
                if (dockStyle != DockStyle.Fill) {
                    preferredSize += neededSize; 
                    remainingBounds.Size += neededSize;
                }
                else if(dockStyle == DockStyle.Fill && CommonProperties.GetAutoSize(element)) {
                    Size elementPrefSize = element.GetPreferredSize(neededSize); 
                    remainingBounds.Size += elementPrefSize;
                    preferredSize += elementPrefSize; 
                } 
            } else {
                element.SetBounds(newElementBounds, BoundsSpecified.None); 

#if DEBUG
                Control control = element as Control;
                newElementBounds.Size = control.ApplySizeConstraints(newElementBounds.Size); 
                // This usually happens when a Control overrides its SetBoundsCore or sets size during OnResize
                // to enforce constraints like AutoSize.  Generally you can just move this code to Control.GetAdjustedSize 
                // and then PreferredSize will also pick up these constraints.  See ComboBox as an example. 
                //
                if (CommonProperties.GetAutoSize(element) && !CommonProperties.GetSelfAutoSizeInDefaultLayout(element)) { 
                    Debug.Assert(
                        (newElementBounds.Width < 0 || element.Bounds.Width == newElementBounds.Width) &&
                        (newElementBounds.Height < 0 || element.Bounds.Height == newElementBounds.Height),
                        "Element modified its bounds during docking -- PreferredSize will be wrong. See comment near this assert."); 
                }
#endif 
            } 
        }
 
        private static Size GetVerticalDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) {
            Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ new Size(remainingSize.Width, 1), measureOnly);

            if (!measureOnly) { 
                newSize.Width = remainingSize.Width;
            } else { 
                newSize.Width = Math.Max(newSize.Width, remainingSize.Width); 
            }
 
            Debug.Assert((measureOnly && (newSize.Width >= remainingSize.Width)) || (newSize.Width == remainingSize.Width),
                "Error detected in GetVerticalDockedSize: Dock size computed incorrectly during layout.");

            return newSize; 
        }
 
        private static Size GetHorizontalDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) { 
            Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ new Size(1, remainingSize.Height), measureOnly);
 
            if (!measureOnly) {
                newSize.Height = remainingSize.Height;
            } else {
                newSize.Height = Math.Max(newSize.Height, remainingSize.Height); 
            }
 
            Debug.Assert((measureOnly && (newSize.Height >= remainingSize.Height)) || (newSize.Height == remainingSize.Height), 
                "Error detected in GetHorizontalDockedSize: Dock size computed incorrectly during layout.");
 
            return newSize;
        }

        //Unused 
        //private static Size GetFillDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) {
        //    Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ remainingSize, measureOnly); 
        //    newSize = LayoutUtils.UnionSizes(newSize, remainingSize); 

        //    if (!measureOnly) { 
        //        newSize = LayoutUtils.IntersectSizes(newSize, remainingSize);
        //    }

        //    Debug.Assert(newSize.Width >= remainingSize.Width && newSize.Height >= remainingSize.Height, 
        //        "Error detected in GetFillDockedSize: Element did not stretch to remaning size.");
        //    Debug.Assert(measureOnly || (newSize.Width == remainingSize.Width && newSize.Height == remainingSize.Height), 
        //        "Error detected in GetFillDockedSize: Dock size computed incorrectly during layout."); 

        //    return newSize; 
        //}

        private static Size xGetDockedSize(IArrangedElement element, Size remainingSize, Size constraints, bool measureOnly) {
            Size desiredSize; 

            if (CommonProperties.GetAutoSize(element)) { 
                // Ask control for its desired size using the provided constraints. 
                // (e.g., a control docked to top will constrain width to remaining width
                // and minimize height.) 
                desiredSize = element.GetPreferredSize(constraints);
            } else {
                desiredSize = element.Bounds.Size;
            } 

            Debug.Assert((desiredSize.Width >= 0 && desiredSize.Height >= 0), "Error detected in xGetDockSize: Element size was negative."); 
            return desiredSize; 
        }
 
        internal override bool LayoutCore(IArrangedElement container, LayoutEventArgs args) {
            Size garbage;     // PreferredSize is garbage if we are not measuring.
            return xLayout(container, /* measureOnly = */ false, out garbage);
        } 

        // Note: PreferredSize is only computed if measureOnly = true. 
        private static bool xLayout(IArrangedElement container, bool measureOnly, out Size preferredSize) { 
        /*
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, 
                              string.Format("{1}(hwnd=0x{0:X}).OnLayout",
                                            (container.IsHandleCreated ? container.Handle : IntPtr.Zero),
                                            container.GetType().FullName));
        */ 

            ArrangedElementCollection children = container.Children; 
            preferredSize = new Size(-7103, -7105);     // PreferredSize is garbage unless measureOnly is specified 

            // short circuit for items with no children 
            if (!measureOnly && children.Count == 0) {
                return CommonProperties.GetAutoSize(container);
            }
 
            bool dock = false;
            bool anchor = false; 
            bool autoSize = false; 

 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = children[i];

                if (CommonProperties.GetNeedsDockAndAnchorLayout(element)) { 
                    if (!dock && CommonProperties.GetNeedsDockLayout(element)) dock = true;
                    if (!anchor && CommonProperties.GetNeedsAnchorLayout(element)) anchor = true; 
                    if (!autoSize && CommonProperties.xGetAutoSizedAndAnchored(element)) autoSize = true; 
                }
            } 

            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tanchor : " + anchor.ToString());
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tdock :   " + dock.ToString());
 
            Size preferredSizeForDocking = Size.Empty;
            Size preferredSizeForAnchoring = Size.Empty; 
 
            if (dock) preferredSizeForDocking = LayoutDockedControls(container, measureOnly);
            if (anchor && !measureOnly) { 
                // in the case of anchor, where we currently are defines the preferred size,
                // so dont recalculate the positions of everything.
                LayoutAnchoredControls(container);
            } 

            if (autoSize) LayoutAutoSizedControls(container); 
 
            if (!measureOnly) {
                // Set the anchored controls to their computed positions. 
                ApplyCachedBounds(container);
            }
            else {
 
                // Finish the preferredSize computation and clear cached anchored positions.
                preferredSizeForAnchoring = GetAnchorPreferredSize(container); 
 
                Padding containerPadding = Padding.Empty;
                Control control = container as Control; 
                if (control != null) {
                   // calling this will respect Control.DefaultPadding.
                   containerPadding = control.Padding;
                } 
                else { // not likely to happen but�
                   containerPadding = CommonProperties.GetPadding(container, Padding.Empty); 
                } 

                preferredSizeForAnchoring.Width -= containerPadding.Left; 
                preferredSizeForAnchoring.Height -= containerPadding.Top;

                ClearCachedBounds(container);
                preferredSize = LayoutUtils.UnionSizes(preferredSizeForDocking, preferredSizeForAnchoring); 

            } 
            return CommonProperties.GetAutoSize(container); 
        }
 
        /// 
        ///     Updates the Anchor information based on the controls current bounds.
        ///     This should only be called when the parent control changes or the
        ///     anchor mode changes. 
        /// 
        private static void UpdateAnchorInfo(IArrangedElement element) { 
            Debug.Assert(!HasCachedBounds(element.Container), 
                "Do not call this method with an active cached bounds list.");
 
            AnchorInfo anchorInfo = GetAnchorInfo(element);
            if(anchorInfo == null) {
                anchorInfo = new AnchorInfo();
                SetAnchorInfo(element, anchorInfo); 
            }
 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Update anchor info"); 
            Debug.Indent();
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, element.Container == null ? "No parent" : "Parent"); 


            if (CommonProperties.GetNeedsAnchorLayout(element) && element.Container != null) {
 
                Rectangle bounds = GetCachedBounds(element);
 
                anchorInfo.Left = element.Bounds.Left; 
                anchorInfo.Top = element.Bounds.Top;
                anchorInfo.Right = element.Bounds.Right; 
                anchorInfo.Bottom = element.Bounds.Bottom;

                Rectangle parentDisplayRect = element.Container.DisplayRectangle;
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Parent displayRectangle" + parentDisplayRect); 
                int parentWidth = parentDisplayRect.Width;
                int parentHeight = parentDisplayRect.Height; 
 
                // VS#46140
                // The anchor is relative to the parent DisplayRectangle, so offset the anchor 
                // by the DisplayRect origin
                anchorInfo.Left -= parentDisplayRect.X;
                anchorInfo.Top -= parentDisplayRect.Y;
                anchorInfo.Right -= parentDisplayRect.X; 
                anchorInfo.Bottom -= parentDisplayRect.Y;
 
                AnchorStyles anchor = GetAnchor(element); 
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    anchorInfo.Right -= parentWidth; 

                    if (!IsAnchored(anchor, AnchorStyles.Left)) {
                        anchorInfo.Left -= parentWidth;
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                    anchorInfo.Right -= (parentWidth/2); 
                    anchorInfo.Left -= (parentWidth/2);
                } 

                if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                    anchorInfo.Bottom -= parentHeight;
 
                    if (!IsAnchored(anchor, AnchorStyles.Top)) {
                        anchorInfo.Top -= parentHeight; 
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Top)) { 
                    anchorInfo.Bottom -= (parentHeight/2);
                    anchorInfo.Top -= (parentHeight/2);
                }
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "anchor info (l,t,r,b): (" + anchorInfo.Left + ", " + anchorInfo.Top  + ", " + anchorInfo.Right  + ", " + anchorInfo.Bottom + ")"); 
            }
            Debug.Unindent(); 
        } 

        public static AnchorStyles GetAnchor(IArrangedElement element) { 
            return CommonProperties.xGetAnchor(element);
        }

        public static void SetAnchor(IArrangedElement container, IArrangedElement element, AnchorStyles value) { 
            AnchorStyles oldValue = GetAnchor(element);
            if (oldValue != value) { 
                if(CommonProperties.GetNeedsDockLayout(element)) { 
                    // We set dock back to none to cause the element to size back to its original bounds.
                    SetDock(element, DockStyle.None); 
                }

                CommonProperties.xSetAnchor(element, value);
 
                if (CommonProperties.GetNeedsAnchorLayout(element)) {
                    UpdateAnchorInfo(element); 
                } 
                else {
                    SetAnchorInfo(element, null); 
                }

                if (element.Container != null) {
                    bool rightReleased = IsAnchored(oldValue, AnchorStyles.Right) && !IsAnchored(value, AnchorStyles.Right); 
                    bool bottomReleased = IsAnchored(oldValue, AnchorStyles.Bottom) && !IsAnchored(value, AnchorStyles.Bottom);
                    if(element.Container.Container != null && (rightReleased || bottomReleased)) { 
                        // If the right or bottom anchor is being released, we have a special case where the element's 
                        // margin may affect preferredSize where it didn't previously.  Rather than do an expensive
                        // check for this in OnLayout, we just detect the case her and force a relayout. 
                        LayoutTransaction.DoLayout(element.Container.Container, element, PropertyNames.Anchor);
                    }
                    LayoutTransaction.DoLayout(element.Container, element, PropertyNames.Anchor);
                } 
            }
            Debug.Assert(GetAnchor(element) == value, "Error setting Anchor value."); 
        } 

        public static DockStyle GetDock(IArrangedElement element) { 
            return CommonProperties.xGetDock(element);
        }

        public static void SetDock(IArrangedElement element, DockStyle value) { 
            Debug.Assert(!HasCachedBounds(element.Container),
                "Do not call this method with an active cached bounds list."); 
 
            if (GetDock(element) != value) {
                //valid values are 0x0 to 0x5 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)DockStyle.None, (int)DockStyle.Fill)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DockStyle));
                }
 
                bool dockNeedsLayout = CommonProperties.GetNeedsDockLayout(element);
                CommonProperties.xSetDock(element, value); 
 
                using (new LayoutTransaction(element.Container as Control, element, PropertyNames.Dock)) {
                    // VSWHDIBEY 227715 if the item is autosized, calling setbounds performs a layout, which 
                    // if we havent set the anchor info properly yet makes dock/anchor layout cranky.

                    if (value == DockStyle.None) {
                        if (dockNeedsLayout) { 
                            // We are transitioning from docked to not docked, restore the original bounds.
                            element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.None); 
                            // VSWHIDBEY 159532 restore Anchor information as its now relevant again. 
                            UpdateAnchorInfo(element);
                        } 
                    }
                    else {
                        // Now setup the new bounds.
                        // 
                        element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.All);
                    } 
                } 

            } 
            Debug.Assert(GetDock(element) == value, "Error setting Dock value.");
        }

        private static Rectangle GetCachedBounds(IArrangedElement element) { 
            if(element.Container != null) {
                IDictionary dictionary = (IDictionary) element.Container.Properties.GetObject(_cachedBoundsProperty); 
                if(dictionary != null) { 
                    object bounds = dictionary[element];
                    if(bounds != null) { 
                        return (Rectangle) bounds;
                    }
                }
            } 
            return element.Bounds;
        } 
 
        private static bool HasCachedBounds(IArrangedElement container) {
            return container != null && container.Properties.GetObject(_cachedBoundsProperty) != null; 
        }

        private static void ApplyCachedBounds(IArrangedElement container) {
            if (CommonProperties.GetAutoSize(container)) { 
                //Avoiding calling DisplayRectangle before checking AutoSize for Everett compat (VSWhidbey 421433)
                Rectangle displayRectangle = container.DisplayRectangle; 
                if ((displayRectangle.Width == 0) || (displayRectangle.Height == 0)) { 
                    ClearCachedBounds(container);
                    return; 
                }
            }

 

            IDictionary dictionary = (IDictionary) container.Properties.GetObject(_cachedBoundsProperty); 
            if(dictionary != null) { 
#if DEBUG
                // In debug builds, we need to modify the collection, so we add a break and an 
                // outer loop to prevent attempting to IEnumerator.MoveNext() on a modified
                // collection.
                while(dictionary.Count > 0) {
#endif 
                foreach(DictionaryEntry entry in dictionary) {
                    IArrangedElement element = (IArrangedElement) entry.Key; 
 
                    Debug.Assert(element.Container == container,"We have non-children in our containers cached bounds store.");
#if DEBUG 
                    // We are about to set the bounds to the cached value.  We clear the cached value
                    // before SetBounds because some controls fiddle with the bounds on SetBounds
                    // and will callback InitLayout with a different bounds and BoundsSpecified.
                    dictionary.Remove(entry.Key); 
#endif
                    Rectangle bounds = (Rectangle) entry.Value; 
                    element.SetBounds(bounds, BoundsSpecified.None); 
#if DEBUG
                    break; 
                }
#endif
                }
                ClearCachedBounds(container); 
            }
        } 
 
        private static void ClearCachedBounds(IArrangedElement container) {
            container.Properties.SetObject(_cachedBoundsProperty, null); 
        }

        private static void SetCachedBounds(IArrangedElement element, Rectangle bounds) {
            if(bounds != GetCachedBounds(element)) { 
                IDictionary dictionary = (IDictionary) element.Container.Properties.GetObject(_cachedBoundsProperty);
                if (dictionary == null) { 
                    dictionary = new HybridDictionary(); 
                    element.Container.Properties.SetObject(_cachedBoundsProperty, dictionary);
                } 
                dictionary[element] = bounds;
            }
        }
 
        private static AnchorInfo GetAnchorInfo(IArrangedElement element) {
            return (AnchorInfo) element.Properties.GetObject(_layoutInfoProperty); 
        } 

        private static void SetAnchorInfo(IArrangedElement element, AnchorInfo value) { 
            element.Properties.SetObject(_layoutInfoProperty, value);
        }

        internal override void InitLayoutCore(IArrangedElement element, BoundsSpecified specified) { 
            Debug.Assert(specified == BoundsSpecified.None || GetCachedBounds(element) == element.Bounds,
                "Attempt to InitLayout while element has active cached bounds."); 
 
            if(specified != BoundsSpecified.None && CommonProperties.GetNeedsAnchorLayout(element)) {
                UpdateAnchorInfo(element); 
            }
        }

        internal override Size GetPreferredSize(IArrangedElement container, Size proposedBounds) { 
            Debug.Assert(!HasCachedBounds(container),
                "Do not call this method with an active cached bounds list."); 
 
            Size prefSize;
 
            xLayout(container, /* measureOnly = */ true, out prefSize);
/*            container.Bounds = prefSize;
            xLayout(container, false, out prefSize);
 
            // make sure controls are big enough to fit on form if not - increase container size
            container.Bounds = newBounds; 
 
            xLayout(container, true, out prefSize);*/
 
            return prefSize;
        }

        private static Size GetAnchorPreferredSize(IArrangedElement container) { 
            Size prefSize = Size.Empty;
 
            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = container.Children[i]; 
                if(!CommonProperties.GetNeedsDockLayout(element) && element.ParticipatesInLayout) {
                    AnchorStyles anchor = GetAnchor(element);
                    Padding margin = CommonProperties.GetMargin(element);
                    Rectangle elementSpace = LayoutUtils.InflateRect(GetCachedBounds(element), margin); 

                    if (IsAnchored(anchor, AnchorStyles.Left) && !IsAnchored(anchor, AnchorStyles.Right)) { 
                        // If we are anchored to the left we make sure the container is large enough not to clip us 
                        // (unless we are right anchored, in which case growing the container will just resize us.)
                        prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right); 
                    }

                    if (/*IsAnchored(anchor, AnchorStyles.Top) &&*/ !IsAnchored(anchor, AnchorStyles.Bottom)) {
                        // If we are anchored to the top we make sure the container is large enough not to clip us 
                        // (unless we are bottom anchored, in which case growing the container will just resize us.)
                        prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom); 
 
                    }
 
                    if (IsAnchored(anchor, AnchorStyles.Right)) {
                        // If we are right anchored, see what the anchor distance between our right edge and
                        // the container is, and make sure our container is large enough to accomodate us.
                        Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/true); 
                        if (anchorDest.Width < 0) {
                            prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right + anchorDest.Width); 
                        } 
                        else {
                            prefSize.Width = Math.Max(prefSize.Width, anchorDest.Right); 
                        }
                    }

                    if (IsAnchored(anchor, AnchorStyles.Bottom)) { 
                        // If we are right anchored, see what the anchor distance between our right edge and
                        // the container is, and make sure our container is large enough to accomodate us. 
                        Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/true); 
                        if (anchorDest.Height < 0) {
                            prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom + anchorDest.Height); 
                        }
                        else {
                            prefSize.Height = Math.Max(prefSize.Height, anchorDest.Bottom);
                        } 
                    }
 
 
                }
            } 
            return prefSize;
        }

        public static bool IsAnchored(AnchorStyles anchor, AnchorStyles desiredAnchor) { 
            return (anchor & desiredAnchor) == desiredAnchor;
        } 
 
        [Flags]
        private enum GrowthDirection { 
            None        = 0,
            Upward      = 0x01,
            Downward    = 0x02,
            Left        = 0x04, 
            Right       = 0x08
        } 
 

#if DEBUG_PAINT_ANCHOR 
 	// handy method for drawing out the child anchor infos
        internal static void  DebugPaintAnchor(Graphics g, Control parent) {
            foreach (Control child in parent.Controls) {
 

                AnchorInfo layout = GetAnchorInfo(child as IArrangedElement); 
                Rectangle displayRect = parent.DisplayRectangle; 

                if (layout == null) { 
                    continue;
                }
                int left = layout.Left + displayRect.X;
                int top = layout.Top + displayRect.Y; 
                int right = layout.Right + displayRect.X;
                int bottom = layout.Bottom + displayRect.Y; 
 
                AnchorStyles anchor = GetAnchor(child as IArrangedElement);
 
                // Repeat of GetAnchorDestination
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting right");
                    right += displayRect.Width; 

                    if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                        Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left"); 
                        left += displayRect.Width;
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Left)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left & right");
                    right += (displayRect.Width / 2); 
                    left += (displayRect.Width / 2);
                } 
 
                if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting bottom"); 
                    bottom += displayRect.Height;

                    if (!IsAnchored(anchor, AnchorStyles.Top)) {
                        Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top"); 
                        top += displayRect.Height;
                    } 
                } 
                else if (!IsAnchored(anchor, AnchorStyles.Top)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top & bottom"); 
                    bottom += (displayRect.Height/2);
                    top += (displayRect.Height/2);
                }
 
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    TextRenderer.DrawText(g, "right " + layout.Right.ToString(), parent.Font, new Point(right/2, child.Top - 20), Color.HotPink); 
                    g.FillRectangle(Brushes.HotPink, 0,  child.Top -4, right, 1); 
                }
                if (IsAnchored(anchor, AnchorStyles.Left)) { 
                    TextRenderer.DrawText(g, "left " + layout.Left.ToString(), parent.Font, new Point(left/2, child.Top - 16), Color.Green);
                    g.FillRectangle(Brushes.Green, 0, child.Top -2, left, 1);
                }
                if (IsAnchored(anchor, AnchorStyles.Top)) { 
                    TextRenderer.DrawText(g, "top " + layout.Top.ToString(), parent.Font, new Point(child.Left -100, top/2), Color.Blue);
 
                    g.FillRectangle(Brushes.Blue, child.Left -1, 0, 1, top); 
                }
                if (IsAnchored(anchor, AnchorStyles.Bottom)) { 
                    TextRenderer.DrawText(g, "bottom " + layout.Bottom.ToString(), parent.Font, new Point(child.Left -100, right/2), Color.Red);
                    g.FillRectangle(Brushes.Red, child.Left -2, 1, 1, bottom);
                }
            } 
        }
#endif 
 
#if DEBUG_LAYOUT
#if DEBUG 

        internal static string Debug_GetAllLayoutInformation(Control start, int indents) {
             string info = Debug_GetLayoutInfo(start, indents) + "\r\n";
 
             for (int i = 0; i < start.Controls.Count; i++) {
                 info += Debug_GetIndents(indents) + "+-->" + Debug_GetAllLayoutInformation(start.Controls[i], indents + 1) + "\r\n"; 
             } 
             return info;
         } 
         internal static string Debug_GetIndents(int indents) {
             string str = "";
             for (int i = 0; i < indents; i++) {
                 str += "\t"; 
             }
             return str; 
         } 
         internal static string Debug_GetLayoutInfo(Control control, int indents) {
             string lineBreak = "\r\n" + Debug_GetIndents(indents + 1); 
             string layoutInfo = string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                "Handle {9} Name {1} Type {2} {0} Bounds {3} {0} AutoSize {4} {0} Dock [{5}] Anchor [{6}] {0} Padding [{7}] Margin [{8}]",
                                                 lineBreak,
                                                 control.Name, 
                                                 control.GetType().Name,
                                                 control.Bounds, 
                                                 control.AutoSize, 
                                                 control.Dock,
                                                 control.Anchor, 
                                                 control.Padding,
                                                 control.Margin,
                                                 !control.IsHandleCreated ? "[not created]" : "0x" + ((int)(control.Handle)).ToString("x"));
             if (control is TableLayoutPanel) { 
                 TypeConverter converter = TypeDescriptor.GetConverter(typeof(TableLayoutSettings));
 
                 layoutInfo += lineBreak + converter.ConvertTo(control as TableLayoutPanel, typeof(string)); 
             }
             return layoutInfo; 

         }
#endif
#endif 

        #region AnchorInfo 
        private sealed class AnchorInfo { 
            public int Left;
            public int Top; 
            public int Right;
            public int Bottom;
        }
        #endregion AnchorInfo 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms.Layout { 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing; 

    using ControlCollection = System.Windows.Forms.Control.ControlCollection; 
    using CompModSwitches = System.ComponentModel.CompModSwitches; 

    internal class DefaultLayout : LayoutEngine { 

        // Singleton instance shared by all controls.
        internal static readonly DefaultLayout Instance = new DefaultLayout();
 
        private static readonly int _layoutInfoProperty = PropertyStore.CreateKey();
        private static readonly int _cachedBoundsProperty = PropertyStore.CreateKey(); 
 
        // Loop through the AutoSized controls and expand them if they are smaller than
        // their preferred size.  If expanding the controls causes overlap, bump the overlapped 
        // control if it is AutoRelocatable.
        private static void LayoutAutoSizedControls(IArrangedElement container) {
            ArrangedElementCollection children = container.Children;
            for (int i = children.Count - 1; i >= 0; i--) { 
                IArrangedElement element = children[i];
 
                if(CommonProperties.xGetAutoSizedAndAnchored(element)) { 
                    Rectangle bounds = GetCachedBounds(element);
 
                    AnchorStyles anchor = GetAnchor(element);
                    Size proposedConstraints = LayoutUtils.MaxSize;

                    if ((anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right)) { 
                        proposedConstraints.Width = bounds.Width;
                    } 
                    if ((anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) { 
                        proposedConstraints.Height = bounds.Height;
                    } 
                    Size prefSize = element.GetPreferredSize(proposedConstraints);

                    Rectangle newBounds = bounds;
 
                    if (CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink) {
                        // this is the case for simple things like radio button, checkbox, etc. 
                        newBounds = GetGrowthBounds(element, prefSize); 
                    }
                    else { 
                        // we had whacked this check, but it turns out it causes undesirable
                        // behavior in things like panel.  a panel with no elements sizes to 0,0.
                        if(bounds.Width < prefSize.Width || bounds.Height < prefSize.Height) {
                            Size newSize = LayoutUtils.UnionSizes(bounds.Size, prefSize); 
                            newBounds = GetGrowthBounds(element, newSize);
                        } 
                    } 
                    if (newBounds != bounds) {
                         SetCachedBounds(element, newBounds); 
                    }
                }
            }
        } 

        // Gets the bounds of the element after growing to newSize (note that depending on 
        // anchoring the element may grow to the left/updwards rather than to the 
        // right/downwards. i.e., it may be translated.)
        private static Rectangle GetGrowthBounds(IArrangedElement element, Size newSize) { 
            GrowthDirection direction = GetGrowthDirection(element);
            Rectangle oldBounds = GetCachedBounds(element);
            Point location = oldBounds.Location;
 
            Debug.Assert((CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink || newSize.Height >= oldBounds.Height && newSize.Width >= oldBounds.Width),
                "newSize expected to be >= current size."); 
 
            if((direction & GrowthDirection.Left) != GrowthDirection.None) {
                // We are growing towards the left, translate X 
                location.X -= newSize.Width - oldBounds.Width;
            }

            if((direction & GrowthDirection.Upward) != GrowthDirection.None) { 
                // We are growing towards the top, translate Y
                location.Y -= newSize.Height - oldBounds.Height; 
            } 

            Rectangle newBounds = new Rectangle(location, newSize); 

            Debug.Assert((CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink || newBounds.Contains(oldBounds)), "How did we resize in such a way we no longer contain our old bounds?");

            return newBounds; 
        }
        // Examines an elements anchoring to figure out which direction it should grow. 
        private static GrowthDirection GetGrowthDirection(IArrangedElement element) { 
            AnchorStyles anchor = GetAnchor(element);
            GrowthDirection growthDirection = GrowthDirection.None; 

            if((anchor & AnchorStyles.Right) != AnchorStyles.None
                && (anchor & AnchorStyles.Left) == AnchorStyles.None) {
                // element is anchored to the right, but not the left. 
                growthDirection |= GrowthDirection.Left;
            } else { 
                // otherwise we grow towards the right (common case) 
                growthDirection |= GrowthDirection.Right;
            } 

            if((anchor & AnchorStyles.Bottom) != AnchorStyles.None
                && (anchor & AnchorStyles.Top) == AnchorStyles.None) {
                // element is anchored to the bottom, but not the top. 
                growthDirection |= GrowthDirection.Upward;
            } else { 
                // otherwise we grow towards the bottom. (common case) 
                growthDirection |= GrowthDirection.Downward;
            } 

            Debug.Assert((growthDirection & GrowthDirection.Left) == GrowthDirection.None
                || (growthDirection & GrowthDirection.Right) == GrowthDirection.None,
                "We shouldn't allow growth to both the left and right."); 
            Debug.Assert((growthDirection & GrowthDirection.Upward) == GrowthDirection.None
                || (growthDirection & GrowthDirection.Downward) == GrowthDirection.None, 
                "We shouldn't allow both upward and downward growth."); 
            return growthDirection;
        } 

        // Layout for a single anchored control.  There's no order dependency when laying out anchored controls.
        private static Rectangle GetAnchorDestination(IArrangedElement element, Rectangle displayRect, bool measureOnly) {
            // Container can not be null since we AschorControls takes a non-null container. 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t'" + element + "' is anchored at " + GetCachedBounds(element).ToString());
 
            AnchorInfo layout = GetAnchorInfo(element); 

            int left = layout.Left + displayRect.X; 
            int top = layout.Top + displayRect.Y;
            int right = layout.Right + displayRect.X;
            int bottom = layout.Bottom + displayRect.Y;
 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...anchor dim (l,t,r,b) {"
                              + (left) 
                              + ", " + (top) 
                              + ", " + (right)
                              + ", " + (bottom) 
                              + "}");

            AnchorStyles anchor = GetAnchor(element);
 
            if (IsAnchored(anchor, AnchorStyles.Right)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting right"); 
                right += displayRect.Width; 

                if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left");
                    left += displayRect.Width;
                }
            } 
            else if (!IsAnchored(anchor, AnchorStyles.Left)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left & right"); 
                right += (displayRect.Width / 2); 
                left += (displayRect.Width / 2);
            } 

            if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting bottom");
                bottom += displayRect.Height; 

                if (!IsAnchored(anchor, AnchorStyles.Top)) { 
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top"); 
                    top += displayRect.Height;
                } 
            }
            else if (!IsAnchored(anchor, AnchorStyles.Top)) {
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top & bottom");
                bottom += (displayRect.Height/2); 
                top += (displayRect.Height/2);
            } 
 
            if (!measureOnly) {
                // the size is actually zero, set the width and heights appropriately. 
                if (right < left) right = left;
                if (bottom < top) bottom = top;
            }
            else { 
                Rectangle cachedBounds = GetCachedBounds(element);
                // in this scenario we've likely been passed a 0 sized display rectangle to determine our height. 
                // we will need to translate the right and bottom edges as necessary to the positive plane. 

                // right < left means the control is anchored both left and right. 
                // cachedBounds != element.Bounds means  the element's size has changed
                // any, all, or none of these can be true.
                if (right < left || cachedBounds.Width != element.Bounds.Width || cachedBounds.X != element.Bounds.X) {
                    if (cachedBounds != element.Bounds) { 
                        left = Math.Max(Math.Abs(left), Math.Abs(cachedBounds.Left));
                    } 
                    right = left + Math.Max(element.Bounds.Width, cachedBounds.Width) + Math.Abs(right); 
                }
                else { 
                    left = left > 0 ? left : element.Bounds.Left;
                    right = right > 0 ? right : element.Bounds.Right + Math.Abs(right);
                }
 
                // bottom < top means the control is anchored both top and bottom.
                // cachedBounds != element.Bounds means  the element's size has changed 
                // any, all, or none of these can be true. 
                if (bottom < top || cachedBounds.Height != element.Bounds.Height || cachedBounds.Y != element.Bounds.Y) {
                    if (cachedBounds != element.Bounds) { 
                        top = Math.Max(Math.Abs(top), Math.Abs(cachedBounds.Top));
                    }
                    bottom = top + Math.Max(element.Bounds.Height, cachedBounds.Height) + Math.Abs(bottom);
                } 
                else {
                    top = top > 0 ? top : element.Bounds.Top; 
                    bottom = bottom > 0 ? bottom : element.Bounds.Bottom + Math.Abs(bottom); 
                }
            } 

            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...new anchor dim (l,t,r,b) {"
                                                                      + (left)
                                                                      + ", " + (top) 
                                                                      + ", " + (right)
                                                                      + ", " + (bottom) 
                                                                      + "}"); 

            return new Rectangle(left, top, right - left, bottom - top); 
        }

        private static void LayoutAnchoredControls(IArrangedElement container) {
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tAnchor Processing"); 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\tdisplayRect: " + container.DisplayRectangle.ToString());
 
            Rectangle displayRectangle = container.DisplayRectangle; 
            if (CommonProperties.GetAutoSize(container) && ((displayRectangle.Width == 0) || (displayRectangle.Height == 0))) {
                // we havent set oursleves to the preferred size yet.  proceeding will 
                // just set all the control widths to zero.  let's return here
                return;
            }
 

            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) { 
                IArrangedElement element = children[i];
 
                if (CommonProperties.GetNeedsAnchorLayout(element)) {
                    Debug.Assert(GetAnchorInfo(element) != null, "AnchorInfo should be initialized before LayoutAnchorControls().");
                    SetCachedBounds(element, GetAnchorDestination(element, displayRectangle, /*measureOnly=*/false));
                } 
            }
        } 
 
        private static Size LayoutDockedControls(IArrangedElement container, bool measureOnly) {
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tDock Processing"); 
            Debug.Assert(!HasCachedBounds(container),
                "Do not call this method with an active cached bounds list.");

            // If measuring, we start with an empty rectangle and add as needed. 
            // If doing actual layout, we start with the container's rect and subtract as we layout.
            Rectangle remainingBounds = measureOnly ? Rectangle.Empty : container.DisplayRectangle; 
            Size preferredSize = Size.Empty; 

            IArrangedElement mdiClient = null; 

            // Docking layout is order dependent. After much debate, we decided to use z-order as the
            // docking order.  (Introducing a DockOrder property was a close second)
            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = children[i]; 
 
                Debug.Assert(element.Bounds == GetCachedBounds(element), "Why do we have cachedBounds for a docked element?");
 
                if (CommonProperties.GetNeedsDockLayout(element)) {
                     // VSWhidbey #109974: Some controls modify their bounds when you call SetBoundsCore.  We
                    // therefore need to read the value of bounds back when adjusting our layout rectangle.
                    switch (GetDock(element)) { 
                        case DockStyle.Top: {
                            Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly); 
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 

                            // What we are really doing here: top += element.Bounds.Height;
                            remainingBounds.Y += element.Bounds.Height;
                            remainingBounds.Height -= element.Bounds.Height; 
                            break;
                        } 
                        case DockStyle.Bottom: { 
                            Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Bottom - elementSize.Height, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds);

                            // What we are really doing here: bottom -= element.Bounds.Height; 
                            remainingBounds.Height -= element.Bounds.Height;
 
                            break; 
                        }
                        case DockStyle.Left: { 
                            Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height);

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 

                            // What we are really doing here: left += element.Bounds.Width; 
                            remainingBounds.X += element.Bounds.Width; 
                            remainingBounds.Width -= element.Bounds.Width;
                            break; 
                        }
                        case DockStyle.Right: {
                            Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly);
                            Rectangle newElementBounds = new Rectangle(remainingBounds.Right - elementSize.Width, remainingBounds.Y, elementSize.Width, elementSize.Height); 

                            xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); 
 
                            // What we are really doing here: right -= element.Bounds.Width;
                            remainingBounds.Width -= element.Bounds.Width; 
                            break;
                        }
                        case DockStyle.Fill:
                            if (element is MdiClient) { 
                                Debug.Assert(mdiClient == null, "How did we end up with multiple MdiClients?");
                                mdiClient = element; 
                            } 
                            else {
                                Size elementSize = remainingBounds.Size;//GetFillDockedSize(element, remainingBounds.Size, measureOnly); 
                                Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height);

                                xLayoutDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds);
                            } 
                            break;
                        default: 
                            Debug.Fail("Unsupported value for dock."); 
                            break;
                    } 
                }

                // Treat the MDI client specially, since it's supposed to blend in with the parent form
                if (mdiClient != null) { 
                    SetCachedBounds(mdiClient, remainingBounds);
                } 
            } 
            return preferredSize;
        } 

        // Helper method that either sets the element bounds or does the preferredSize computation based on
        // the value of measureOnly.
        private static void xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, bool measureOnly, ref Size preferredSize, ref Rectangle remainingBounds) { 
            if (measureOnly) {
                Size neededSize = new Size( 
                    Math.Max(0, newElementBounds.Width - remainingBounds.Width), 
                    Math.Max(0, newElementBounds.Height - remainingBounds.Height));
 
                DockStyle dockStyle = GetDock(element);
                if ((dockStyle == DockStyle.Top) || (dockStyle == DockStyle.Bottom)) {
                    neededSize.Width = 0;
                } 
                if ((dockStyle == DockStyle.Left) || (dockStyle == DockStyle.Right)) {
                    neededSize.Height = 0; 
                } 
                if (dockStyle != DockStyle.Fill) {
                    preferredSize += neededSize; 
                    remainingBounds.Size += neededSize;
                }
                else if(dockStyle == DockStyle.Fill && CommonProperties.GetAutoSize(element)) {
                    Size elementPrefSize = element.GetPreferredSize(neededSize); 
                    remainingBounds.Size += elementPrefSize;
                    preferredSize += elementPrefSize; 
                } 
            } else {
                element.SetBounds(newElementBounds, BoundsSpecified.None); 

#if DEBUG
                Control control = element as Control;
                newElementBounds.Size = control.ApplySizeConstraints(newElementBounds.Size); 
                // This usually happens when a Control overrides its SetBoundsCore or sets size during OnResize
                // to enforce constraints like AutoSize.  Generally you can just move this code to Control.GetAdjustedSize 
                // and then PreferredSize will also pick up these constraints.  See ComboBox as an example. 
                //
                if (CommonProperties.GetAutoSize(element) && !CommonProperties.GetSelfAutoSizeInDefaultLayout(element)) { 
                    Debug.Assert(
                        (newElementBounds.Width < 0 || element.Bounds.Width == newElementBounds.Width) &&
                        (newElementBounds.Height < 0 || element.Bounds.Height == newElementBounds.Height),
                        "Element modified its bounds during docking -- PreferredSize will be wrong. See comment near this assert."); 
                }
#endif 
            } 
        }
 
        private static Size GetVerticalDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) {
            Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ new Size(remainingSize.Width, 1), measureOnly);

            if (!measureOnly) { 
                newSize.Width = remainingSize.Width;
            } else { 
                newSize.Width = Math.Max(newSize.Width, remainingSize.Width); 
            }
 
            Debug.Assert((measureOnly && (newSize.Width >= remainingSize.Width)) || (newSize.Width == remainingSize.Width),
                "Error detected in GetVerticalDockedSize: Dock size computed incorrectly during layout.");

            return newSize; 
        }
 
        private static Size GetHorizontalDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) { 
            Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ new Size(1, remainingSize.Height), measureOnly);
 
            if (!measureOnly) {
                newSize.Height = remainingSize.Height;
            } else {
                newSize.Height = Math.Max(newSize.Height, remainingSize.Height); 
            }
 
            Debug.Assert((measureOnly && (newSize.Height >= remainingSize.Height)) || (newSize.Height == remainingSize.Height), 
                "Error detected in GetHorizontalDockedSize: Dock size computed incorrectly during layout.");
 
            return newSize;
        }

        //Unused 
        //private static Size GetFillDockedSize(IArrangedElement element, Size remainingSize, bool measureOnly) {
        //    Size newSize = xGetDockedSize(element, remainingSize, /* constraints = */ remainingSize, measureOnly); 
        //    newSize = LayoutUtils.UnionSizes(newSize, remainingSize); 

        //    if (!measureOnly) { 
        //        newSize = LayoutUtils.IntersectSizes(newSize, remainingSize);
        //    }

        //    Debug.Assert(newSize.Width >= remainingSize.Width && newSize.Height >= remainingSize.Height, 
        //        "Error detected in GetFillDockedSize: Element did not stretch to remaning size.");
        //    Debug.Assert(measureOnly || (newSize.Width == remainingSize.Width && newSize.Height == remainingSize.Height), 
        //        "Error detected in GetFillDockedSize: Dock size computed incorrectly during layout."); 

        //    return newSize; 
        //}

        private static Size xGetDockedSize(IArrangedElement element, Size remainingSize, Size constraints, bool measureOnly) {
            Size desiredSize; 

            if (CommonProperties.GetAutoSize(element)) { 
                // Ask control for its desired size using the provided constraints. 
                // (e.g., a control docked to top will constrain width to remaining width
                // and minimize height.) 
                desiredSize = element.GetPreferredSize(constraints);
            } else {
                desiredSize = element.Bounds.Size;
            } 

            Debug.Assert((desiredSize.Width >= 0 && desiredSize.Height >= 0), "Error detected in xGetDockSize: Element size was negative."); 
            return desiredSize; 
        }
 
        internal override bool LayoutCore(IArrangedElement container, LayoutEventArgs args) {
            Size garbage;     // PreferredSize is garbage if we are not measuring.
            return xLayout(container, /* measureOnly = */ false, out garbage);
        } 

        // Note: PreferredSize is only computed if measureOnly = true. 
        private static bool xLayout(IArrangedElement container, bool measureOnly, out Size preferredSize) { 
        /*
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, 
                              string.Format("{1}(hwnd=0x{0:X}).OnLayout",
                                            (container.IsHandleCreated ? container.Handle : IntPtr.Zero),
                                            container.GetType().FullName));
        */ 

            ArrangedElementCollection children = container.Children; 
            preferredSize = new Size(-7103, -7105);     // PreferredSize is garbage unless measureOnly is specified 

            // short circuit for items with no children 
            if (!measureOnly && children.Count == 0) {
                return CommonProperties.GetAutoSize(container);
            }
 
            bool dock = false;
            bool anchor = false; 
            bool autoSize = false; 

 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = children[i];

                if (CommonProperties.GetNeedsDockAndAnchorLayout(element)) { 
                    if (!dock && CommonProperties.GetNeedsDockLayout(element)) dock = true;
                    if (!anchor && CommonProperties.GetNeedsAnchorLayout(element)) anchor = true; 
                    if (!autoSize && CommonProperties.xGetAutoSizedAndAnchored(element)) autoSize = true; 
                }
            } 

            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tanchor : " + anchor.ToString());
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tdock :   " + dock.ToString());
 
            Size preferredSizeForDocking = Size.Empty;
            Size preferredSizeForAnchoring = Size.Empty; 
 
            if (dock) preferredSizeForDocking = LayoutDockedControls(container, measureOnly);
            if (anchor && !measureOnly) { 
                // in the case of anchor, where we currently are defines the preferred size,
                // so dont recalculate the positions of everything.
                LayoutAnchoredControls(container);
            } 

            if (autoSize) LayoutAutoSizedControls(container); 
 
            if (!measureOnly) {
                // Set the anchored controls to their computed positions. 
                ApplyCachedBounds(container);
            }
            else {
 
                // Finish the preferredSize computation and clear cached anchored positions.
                preferredSizeForAnchoring = GetAnchorPreferredSize(container); 
 
                Padding containerPadding = Padding.Empty;
                Control control = container as Control; 
                if (control != null) {
                   // calling this will respect Control.DefaultPadding.
                   containerPadding = control.Padding;
                } 
                else { // not likely to happen but�
                   containerPadding = CommonProperties.GetPadding(container, Padding.Empty); 
                } 

                preferredSizeForAnchoring.Width -= containerPadding.Left; 
                preferredSizeForAnchoring.Height -= containerPadding.Top;

                ClearCachedBounds(container);
                preferredSize = LayoutUtils.UnionSizes(preferredSizeForDocking, preferredSizeForAnchoring); 

            } 
            return CommonProperties.GetAutoSize(container); 
        }
 
        /// 
        ///     Updates the Anchor information based on the controls current bounds.
        ///     This should only be called when the parent control changes or the
        ///     anchor mode changes. 
        /// 
        private static void UpdateAnchorInfo(IArrangedElement element) { 
            Debug.Assert(!HasCachedBounds(element.Container), 
                "Do not call this method with an active cached bounds list.");
 
            AnchorInfo anchorInfo = GetAnchorInfo(element);
            if(anchorInfo == null) {
                anchorInfo = new AnchorInfo();
                SetAnchorInfo(element, anchorInfo); 
            }
 
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Update anchor info"); 
            Debug.Indent();
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, element.Container == null ? "No parent" : "Parent"); 


            if (CommonProperties.GetNeedsAnchorLayout(element) && element.Container != null) {
 
                Rectangle bounds = GetCachedBounds(element);
 
                anchorInfo.Left = element.Bounds.Left; 
                anchorInfo.Top = element.Bounds.Top;
                anchorInfo.Right = element.Bounds.Right; 
                anchorInfo.Bottom = element.Bounds.Bottom;

                Rectangle parentDisplayRect = element.Container.DisplayRectangle;
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Parent displayRectangle" + parentDisplayRect); 
                int parentWidth = parentDisplayRect.Width;
                int parentHeight = parentDisplayRect.Height; 
 
                // VS#46140
                // The anchor is relative to the parent DisplayRectangle, so offset the anchor 
                // by the DisplayRect origin
                anchorInfo.Left -= parentDisplayRect.X;
                anchorInfo.Top -= parentDisplayRect.Y;
                anchorInfo.Right -= parentDisplayRect.X; 
                anchorInfo.Bottom -= parentDisplayRect.Y;
 
                AnchorStyles anchor = GetAnchor(element); 
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    anchorInfo.Right -= parentWidth; 

                    if (!IsAnchored(anchor, AnchorStyles.Left)) {
                        anchorInfo.Left -= parentWidth;
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                    anchorInfo.Right -= (parentWidth/2); 
                    anchorInfo.Left -= (parentWidth/2);
                } 

                if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                    anchorInfo.Bottom -= parentHeight;
 
                    if (!IsAnchored(anchor, AnchorStyles.Top)) {
                        anchorInfo.Top -= parentHeight; 
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Top)) { 
                    anchorInfo.Bottom -= (parentHeight/2);
                    anchorInfo.Top -= (parentHeight/2);
                }
                Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "anchor info (l,t,r,b): (" + anchorInfo.Left + ", " + anchorInfo.Top  + ", " + anchorInfo.Right  + ", " + anchorInfo.Bottom + ")"); 
            }
            Debug.Unindent(); 
        } 

        public static AnchorStyles GetAnchor(IArrangedElement element) { 
            return CommonProperties.xGetAnchor(element);
        }

        public static void SetAnchor(IArrangedElement container, IArrangedElement element, AnchorStyles value) { 
            AnchorStyles oldValue = GetAnchor(element);
            if (oldValue != value) { 
                if(CommonProperties.GetNeedsDockLayout(element)) { 
                    // We set dock back to none to cause the element to size back to its original bounds.
                    SetDock(element, DockStyle.None); 
                }

                CommonProperties.xSetAnchor(element, value);
 
                if (CommonProperties.GetNeedsAnchorLayout(element)) {
                    UpdateAnchorInfo(element); 
                } 
                else {
                    SetAnchorInfo(element, null); 
                }

                if (element.Container != null) {
                    bool rightReleased = IsAnchored(oldValue, AnchorStyles.Right) && !IsAnchored(value, AnchorStyles.Right); 
                    bool bottomReleased = IsAnchored(oldValue, AnchorStyles.Bottom) && !IsAnchored(value, AnchorStyles.Bottom);
                    if(element.Container.Container != null && (rightReleased || bottomReleased)) { 
                        // If the right or bottom anchor is being released, we have a special case where the element's 
                        // margin may affect preferredSize where it didn't previously.  Rather than do an expensive
                        // check for this in OnLayout, we just detect the case her and force a relayout. 
                        LayoutTransaction.DoLayout(element.Container.Container, element, PropertyNames.Anchor);
                    }
                    LayoutTransaction.DoLayout(element.Container, element, PropertyNames.Anchor);
                } 
            }
            Debug.Assert(GetAnchor(element) == value, "Error setting Anchor value."); 
        } 

        public static DockStyle GetDock(IArrangedElement element) { 
            return CommonProperties.xGetDock(element);
        }

        public static void SetDock(IArrangedElement element, DockStyle value) { 
            Debug.Assert(!HasCachedBounds(element.Container),
                "Do not call this method with an active cached bounds list."); 
 
            if (GetDock(element) != value) {
                //valid values are 0x0 to 0x5 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)DockStyle.None, (int)DockStyle.Fill)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DockStyle));
                }
 
                bool dockNeedsLayout = CommonProperties.GetNeedsDockLayout(element);
                CommonProperties.xSetDock(element, value); 
 
                using (new LayoutTransaction(element.Container as Control, element, PropertyNames.Dock)) {
                    // VSWHDIBEY 227715 if the item is autosized, calling setbounds performs a layout, which 
                    // if we havent set the anchor info properly yet makes dock/anchor layout cranky.

                    if (value == DockStyle.None) {
                        if (dockNeedsLayout) { 
                            // We are transitioning from docked to not docked, restore the original bounds.
                            element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.None); 
                            // VSWHIDBEY 159532 restore Anchor information as its now relevant again. 
                            UpdateAnchorInfo(element);
                        } 
                    }
                    else {
                        // Now setup the new bounds.
                        // 
                        element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.All);
                    } 
                } 

            } 
            Debug.Assert(GetDock(element) == value, "Error setting Dock value.");
        }

        private static Rectangle GetCachedBounds(IArrangedElement element) { 
            if(element.Container != null) {
                IDictionary dictionary = (IDictionary) element.Container.Properties.GetObject(_cachedBoundsProperty); 
                if(dictionary != null) { 
                    object bounds = dictionary[element];
                    if(bounds != null) { 
                        return (Rectangle) bounds;
                    }
                }
            } 
            return element.Bounds;
        } 
 
        private static bool HasCachedBounds(IArrangedElement container) {
            return container != null && container.Properties.GetObject(_cachedBoundsProperty) != null; 
        }

        private static void ApplyCachedBounds(IArrangedElement container) {
            if (CommonProperties.GetAutoSize(container)) { 
                //Avoiding calling DisplayRectangle before checking AutoSize for Everett compat (VSWhidbey 421433)
                Rectangle displayRectangle = container.DisplayRectangle; 
                if ((displayRectangle.Width == 0) || (displayRectangle.Height == 0)) { 
                    ClearCachedBounds(container);
                    return; 
                }
            }

 

            IDictionary dictionary = (IDictionary) container.Properties.GetObject(_cachedBoundsProperty); 
            if(dictionary != null) { 
#if DEBUG
                // In debug builds, we need to modify the collection, so we add a break and an 
                // outer loop to prevent attempting to IEnumerator.MoveNext() on a modified
                // collection.
                while(dictionary.Count > 0) {
#endif 
                foreach(DictionaryEntry entry in dictionary) {
                    IArrangedElement element = (IArrangedElement) entry.Key; 
 
                    Debug.Assert(element.Container == container,"We have non-children in our containers cached bounds store.");
#if DEBUG 
                    // We are about to set the bounds to the cached value.  We clear the cached value
                    // before SetBounds because some controls fiddle with the bounds on SetBounds
                    // and will callback InitLayout with a different bounds and BoundsSpecified.
                    dictionary.Remove(entry.Key); 
#endif
                    Rectangle bounds = (Rectangle) entry.Value; 
                    element.SetBounds(bounds, BoundsSpecified.None); 
#if DEBUG
                    break; 
                }
#endif
                }
                ClearCachedBounds(container); 
            }
        } 
 
        private static void ClearCachedBounds(IArrangedElement container) {
            container.Properties.SetObject(_cachedBoundsProperty, null); 
        }

        private static void SetCachedBounds(IArrangedElement element, Rectangle bounds) {
            if(bounds != GetCachedBounds(element)) { 
                IDictionary dictionary = (IDictionary) element.Container.Properties.GetObject(_cachedBoundsProperty);
                if (dictionary == null) { 
                    dictionary = new HybridDictionary(); 
                    element.Container.Properties.SetObject(_cachedBoundsProperty, dictionary);
                } 
                dictionary[element] = bounds;
            }
        }
 
        private static AnchorInfo GetAnchorInfo(IArrangedElement element) {
            return (AnchorInfo) element.Properties.GetObject(_layoutInfoProperty); 
        } 

        private static void SetAnchorInfo(IArrangedElement element, AnchorInfo value) { 
            element.Properties.SetObject(_layoutInfoProperty, value);
        }

        internal override void InitLayoutCore(IArrangedElement element, BoundsSpecified specified) { 
            Debug.Assert(specified == BoundsSpecified.None || GetCachedBounds(element) == element.Bounds,
                "Attempt to InitLayout while element has active cached bounds."); 
 
            if(specified != BoundsSpecified.None && CommonProperties.GetNeedsAnchorLayout(element)) {
                UpdateAnchorInfo(element); 
            }
        }

        internal override Size GetPreferredSize(IArrangedElement container, Size proposedBounds) { 
            Debug.Assert(!HasCachedBounds(container),
                "Do not call this method with an active cached bounds list."); 
 
            Size prefSize;
 
            xLayout(container, /* measureOnly = */ true, out prefSize);
/*            container.Bounds = prefSize;
            xLayout(container, false, out prefSize);
 
            // make sure controls are big enough to fit on form if not - increase container size
            container.Bounds = newBounds; 
 
            xLayout(container, true, out prefSize);*/
 
            return prefSize;
        }

        private static Size GetAnchorPreferredSize(IArrangedElement container) { 
            Size prefSize = Size.Empty;
 
            ArrangedElementCollection children = container.Children; 
            for (int i = children.Count - 1; i >= 0; i--) {
                IArrangedElement element = container.Children[i]; 
                if(!CommonProperties.GetNeedsDockLayout(element) && element.ParticipatesInLayout) {
                    AnchorStyles anchor = GetAnchor(element);
                    Padding margin = CommonProperties.GetMargin(element);
                    Rectangle elementSpace = LayoutUtils.InflateRect(GetCachedBounds(element), margin); 

                    if (IsAnchored(anchor, AnchorStyles.Left) && !IsAnchored(anchor, AnchorStyles.Right)) { 
                        // If we are anchored to the left we make sure the container is large enough not to clip us 
                        // (unless we are right anchored, in which case growing the container will just resize us.)
                        prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right); 
                    }

                    if (/*IsAnchored(anchor, AnchorStyles.Top) &&*/ !IsAnchored(anchor, AnchorStyles.Bottom)) {
                        // If we are anchored to the top we make sure the container is large enough not to clip us 
                        // (unless we are bottom anchored, in which case growing the container will just resize us.)
                        prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom); 
 
                    }
 
                    if (IsAnchored(anchor, AnchorStyles.Right)) {
                        // If we are right anchored, see what the anchor distance between our right edge and
                        // the container is, and make sure our container is large enough to accomodate us.
                        Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/true); 
                        if (anchorDest.Width < 0) {
                            prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right + anchorDest.Width); 
                        } 
                        else {
                            prefSize.Width = Math.Max(prefSize.Width, anchorDest.Right); 
                        }
                    }

                    if (IsAnchored(anchor, AnchorStyles.Bottom)) { 
                        // If we are right anchored, see what the anchor distance between our right edge and
                        // the container is, and make sure our container is large enough to accomodate us. 
                        Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/true); 
                        if (anchorDest.Height < 0) {
                            prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom + anchorDest.Height); 
                        }
                        else {
                            prefSize.Height = Math.Max(prefSize.Height, anchorDest.Bottom);
                        } 
                    }
 
 
                }
            } 
            return prefSize;
        }

        public static bool IsAnchored(AnchorStyles anchor, AnchorStyles desiredAnchor) { 
            return (anchor & desiredAnchor) == desiredAnchor;
        } 
 
        [Flags]
        private enum GrowthDirection { 
            None        = 0,
            Upward      = 0x01,
            Downward    = 0x02,
            Left        = 0x04, 
            Right       = 0x08
        } 
 

#if DEBUG_PAINT_ANCHOR 
 	// handy method for drawing out the child anchor infos
        internal static void  DebugPaintAnchor(Graphics g, Control parent) {
            foreach (Control child in parent.Controls) {
 

                AnchorInfo layout = GetAnchorInfo(child as IArrangedElement); 
                Rectangle displayRect = parent.DisplayRectangle; 

                if (layout == null) { 
                    continue;
                }
                int left = layout.Left + displayRect.X;
                int top = layout.Top + displayRect.Y; 
                int right = layout.Right + displayRect.X;
                int bottom = layout.Bottom + displayRect.Y; 
 
                AnchorStyles anchor = GetAnchor(child as IArrangedElement);
 
                // Repeat of GetAnchorDestination
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting right");
                    right += displayRect.Width; 

                    if (!IsAnchored(anchor, AnchorStyles.Left)) { 
                        Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left"); 
                        left += displayRect.Width;
                    } 
                }
                else if (!IsAnchored(anchor, AnchorStyles.Left)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting left & right");
                    right += (displayRect.Width / 2); 
                    left += (displayRect.Width / 2);
                } 
 
                if (IsAnchored(anchor, AnchorStyles.Bottom)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting bottom"); 
                    bottom += displayRect.Height;

                    if (!IsAnchored(anchor, AnchorStyles.Top)) {
                        Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top"); 
                        top += displayRect.Height;
                    } 
                } 
                else if (!IsAnchored(anchor, AnchorStyles.Top)) {
                    Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\t\t...adjusting top & bottom"); 
                    bottom += (displayRect.Height/2);
                    top += (displayRect.Height/2);
                }
 
                if (IsAnchored(anchor, AnchorStyles.Right)) {
                    TextRenderer.DrawText(g, "right " + layout.Right.ToString(), parent.Font, new Point(right/2, child.Top - 20), Color.HotPink); 
                    g.FillRectangle(Brushes.HotPink, 0,  child.Top -4, right, 1); 
                }
                if (IsAnchored(anchor, AnchorStyles.Left)) { 
                    TextRenderer.DrawText(g, "left " + layout.Left.ToString(), parent.Font, new Point(left/2, child.Top - 16), Color.Green);
                    g.FillRectangle(Brushes.Green, 0, child.Top -2, left, 1);
                }
                if (IsAnchored(anchor, AnchorStyles.Top)) { 
                    TextRenderer.DrawText(g, "top " + layout.Top.ToString(), parent.Font, new Point(child.Left -100, top/2), Color.Blue);
 
                    g.FillRectangle(Brushes.Blue, child.Left -1, 0, 1, top); 
                }
                if (IsAnchored(anchor, AnchorStyles.Bottom)) { 
                    TextRenderer.DrawText(g, "bottom " + layout.Bottom.ToString(), parent.Font, new Point(child.Left -100, right/2), Color.Red);
                    g.FillRectangle(Brushes.Red, child.Left -2, 1, 1, bottom);
                }
            } 
        }
#endif 
 
#if DEBUG_LAYOUT
#if DEBUG 

        internal static string Debug_GetAllLayoutInformation(Control start, int indents) {
             string info = Debug_GetLayoutInfo(start, indents) + "\r\n";
 
             for (int i = 0; i < start.Controls.Count; i++) {
                 info += Debug_GetIndents(indents) + "+-->" + Debug_GetAllLayoutInformation(start.Controls[i], indents + 1) + "\r\n"; 
             } 
             return info;
         } 
         internal static string Debug_GetIndents(int indents) {
             string str = "";
             for (int i = 0; i < indents; i++) {
                 str += "\t"; 
             }
             return str; 
         } 
         internal static string Debug_GetLayoutInfo(Control control, int indents) {
             string lineBreak = "\r\n" + Debug_GetIndents(indents + 1); 
             string layoutInfo = string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                "Handle {9} Name {1} Type {2} {0} Bounds {3} {0} AutoSize {4} {0} Dock [{5}] Anchor [{6}] {0} Padding [{7}] Margin [{8}]",
                                                 lineBreak,
                                                 control.Name, 
                                                 control.GetType().Name,
                                                 control.Bounds, 
                                                 control.AutoSize, 
                                                 control.Dock,
                                                 control.Anchor, 
                                                 control.Padding,
                                                 control.Margin,
                                                 !control.IsHandleCreated ? "[not created]" : "0x" + ((int)(control.Handle)).ToString("x"));
             if (control is TableLayoutPanel) { 
                 TypeConverter converter = TypeDescriptor.GetConverter(typeof(TableLayoutSettings));
 
                 layoutInfo += lineBreak + converter.ConvertTo(control as TableLayoutPanel, typeof(string)); 
             }
             return layoutInfo; 

         }
#endif
#endif 

        #region AnchorInfo 
        private sealed class AnchorInfo { 
            public int Left;
            public int Top; 
            public int Right;
            public int Bottom;
        }
        #endregion AnchorInfo 
    }
} 

// 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