Grid.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / Grid.cs / 1 / Grid.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Grid implementation. 
//
// Specs 
//      Grid : http://avalon/layout/Specs/Grid.mht
//      Size Sharing: http://avalon/layout/Specs/Size%20Information%20Sharing.doc
//
// Misc 
//      Grid Tutorial: http://avalon/layout/Documentation%20and%20Tutorials/Grid%20Tutorial.mht
// 
// History: 
//  09/24/2003 : olego - Created (in griddy prototype branch);
//  10/27/2003 : olego - Ported from griddy prototype branch; 
//  01/20/2004 : olego - Switching to use UIElementCollection;
//
//
 

 
 

 



 

 
 

 



 
using MS.Internal;
using MS.Internal.Controls; 
using MS.Internal.PresentationFramework; 
using MS.Utility;
 
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics; 
using System.Windows.Threading;
using System.Threading; 
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Documents; 
using System.Windows.Media;
using System.Windows.Markup;

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 

namespace System.Windows.Controls 
{ 

    ///  
    /// Grid
    /// 
    public class Grid : Panel, IAddChild
    { 

        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        /// 
        /// Default constructor. 
        ///  
        public Grid()
        { 
            SetFlags((bool) ShowGridLinesProperty.GetDefaultValue(DependencyObjectType), Flags.ShowGridLinesPropertyValue);
        }

        #endregion Constructors 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        ///  
        ///  
        void IAddChild.AddChild(object value)
        { 
            if (value == null)
            {
                throw new ArgumentNullException("value");
            } 

            UIElement cell = value as UIElement; 
            if (cell != null) 
            {
                Children.Add(cell); 
                return;
            }

            throw (new ArgumentException(SR.Get(SRID.Grid_UnexpectedParameterType, value.GetType(), typeof(UIElement)), "value")); 
        }
 
        ///  
        /// 
        ///  
        void IAddChild.AddText(string text)
        {
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this);
        } 

        ///  
        ///  
        /// 
        protected internal override IEnumerator LogicalChildren 
        {
            get
            {
                // empty panel or a panel being used as the items 
                // host has *no* logical children; give empty enumerator
                bool noChildren = (base.VisualChildrenCount == 0) || IsItemsHost; 
 
                if (noChildren)
                { 
                    ExtendedData extData = ExtData;

                    if (    extData == null
                        ||  (   (extData.ColumnDefinitions == null || extData.ColumnDefinitions.Count == 0) 
                            &&  (extData.RowDefinitions    == null || extData.RowDefinitions.Count    == 0) )
                       ) 
                    { 
                        //  grid is empty
                        return EmptyEnumerator.Instance; 
                    }
                }

                return (new GridChildrenCollectionEnumeratorSimple(this, !noChildren)); 
            }
        } 
 
        /// 
        /// Helper for setting Column property on a UIElement. 
        /// 
        /// UIElement to set Column property on.
        /// Column property value.
        public static void SetColumn(UIElement element, int value) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            element.SetValue(ColumnProperty, value);
        }
 
        /// 
        /// Helper for reading Column property from a UIElement. 
        ///  
        /// UIElement to read Column property from.
        /// Column property value. 
        [AttachedPropertyBrowsableForChildren()]
        public static int GetColumn(UIElement element)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            return ((int)element.GetValue(ColumnProperty)); 
        }

        /// 
        /// Helper for setting Row property on a UIElement. 
        /// 
        /// UIElement to set Row property on. 
        /// Row property value. 
        public static void SetRow(UIElement element, int value)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            element.SetValue(RowProperty, value); 
        } 

        ///  
        /// Helper for reading Row property from a UIElement.
        /// 
        /// UIElement to read Row property from.
        /// Row property value. 
        [AttachedPropertyBrowsableForChildren()]
        public static int GetRow(UIElement element) 
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            }

            return ((int)element.GetValue(RowProperty)); 
        }
 
        ///  
        /// Helper for setting ColumnSpan property on a UIElement.
        ///  
        /// UIElement to set ColumnSpan property on.
        /// ColumnSpan property value.
        public static void SetColumnSpan(UIElement element, int value)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            element.SetValue(ColumnSpanProperty, value);
        }

        ///  
        /// Helper for reading ColumnSpan property from a UIElement.
        ///  
        /// UIElement to read ColumnSpan property from. 
        /// ColumnSpan property value.
        [AttachedPropertyBrowsableForChildren()] 
        public static int GetColumnSpan(UIElement element)
        {
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            } 
 
            return ((int)element.GetValue(ColumnSpanProperty));
        } 

        /// 
        /// Helper for setting RowSpan property on a UIElement.
        ///  
        /// UIElement to set RowSpan property on.
        /// RowSpan property value. 
        public static void SetRowSpan(UIElement element, int value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(RowSpanProperty, value);
        } 
 
        /// 
        /// Helper for reading RowSpan property from a UIElement. 
        /// 
        /// UIElement to read RowSpan property from.
        /// RowSpan property value.
        [AttachedPropertyBrowsableForChildren()] 
        public static int GetRowSpan(UIElement element)
        { 
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            }

            return ((int)element.GetValue(RowSpanProperty));
        } 

        ///  
        /// Helper for setting IsSharedSizeScope property on a UIElement. 
        /// 
        /// UIElement to set IsSharedSizeScope property on. 
        /// IsSharedSizeScope property value.
        public static void SetIsSharedSizeScope(UIElement element, bool value)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            element.SetValue(IsSharedSizeScopeProperty, value); 
        }

        /// 
        /// Helper for reading IsSharedSizeScope property from a UIElement. 
        /// 
        /// UIElement to read IsSharedSizeScope property from. 
        /// IsSharedSizeScope property value. 
        public static bool GetIsSharedSizeScope(UIElement element)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            return ((bool)element.GetValue(IsSharedSizeScopeProperty)); 
        } 

        #endregion Public Methods 

        //------------------------------------------------------
        //
        //  Public Properties 
        //
        //------------------------------------------------------ 
 
        #region Public Properties
 
        /// 
        /// ShowGridLines property.
        /// 
        public bool ShowGridLines 
        {
            get { return (CheckFlagsAnd(Flags.ShowGridLinesPropertyValue)); } 
            set { SetValue(ShowGridLinesProperty, value); } 
        }
 
        /// 
        /// Returns a ColumnDefinitionCollection of column definitions.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public ColumnDefinitionCollection ColumnDefinitions
        { 
            get 
            {
                if (_data == null) { _data = new ExtendedData(); } 
                if (_data.ColumnDefinitions == null) { _data.ColumnDefinitions = new ColumnDefinitionCollection(this); }

                return (_data.ColumnDefinitions);
            } 
        }
 
        ///  
        /// Returns a RowDefinitionCollection of row definitions.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public RowDefinitionCollection RowDefinitions
        {
            get 
            {
                if (_data == null) { _data = new ExtendedData(); } 
                if (_data.RowDefinitions == null) { _data.RowDefinitions = new RowDefinitionCollection(this); } 

                return (_data.RowDefinitions); 
            }
        }

        #endregion Public Properties 

        //----------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------

        #region Protected Methods
 
        /// 
        ///   Derived class must implement to support Visual children. The method must return 
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        ///
        ///    By default a Visual does not have any children. 
        ///
        ///  Remark:
        ///       During this virtual call it is not valid to modify the Visual tree.
        ///  
        protected override Visual GetVisualChild(int index)
        { 
            // because "base.Count + 1" for GridLinesRenderer 
            // argument checking done at the base class
            if(index == base.VisualChildrenCount) 
            {
                if (_gridLinesRenderer == null)
                {
                    throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
                }
                return _gridLinesRenderer; 
            } 
            else return base.GetVisualChild(index);
 
        }

        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate 
        ///  the Visual children. Derived classes need to return the number of children
        ///  from this method. 
        /// 
        ///    By default a Visual does not have any children.
        /// 
        ///  Remark: During this virtual method the Visual tree must not be modified.
        /// 
        protected override int VisualChildrenCount
        { 
            //since GridLinesRenderer has not been added as a child, so we do not subtract
            get { return base.VisualChildrenCount + (_gridLinesRenderer != null ? 1 : 0); } 
        } 

 
        /// 
        /// Content measurement.
        /// 
        /// Constraint 
        /// Desired size
        protected override Size MeasureOverride(Size constraint) 
        { 
            Size gridDesiredSize;
            ExtendedData extData = ExtData; 

            try
            {
                EnterCounterScope(Counters.MeasureOverride); 

                ListenToNotifications = true; 
                MeasureOverrideInProgress = true; 

                if (extData == null) 
                {
                    gridDesiredSize = new Size();
                    UIElementCollection children = InternalChildren;
 
                    for (int i = 0, count = children.Count; i < count; ++i)
                    { 
                        UIElement child = children[i]; 
                        if (child != null)
                        { 
                            Helper.SetMeasureDataOnChild(this, child, constraint);  // pass along MeasureData so it continues down the tree.
                            child.Measure(constraint);
                            gridDesiredSize.Width = Math.Max(gridDesiredSize.Width, child.DesiredSize.Width);
                            gridDesiredSize.Height = Math.Max(gridDesiredSize.Height, child.DesiredSize.Height); 
                        }
                    } 
                } 
                else
                { 
                    {
                        bool sizeToContentU = double.IsPositiveInfinity(constraint.Width);
                        bool sizeToContentV = double.IsPositiveInfinity(constraint.Height);
 
                        ValidateDefinitionsUStructure();
                        ValidateDefinitionsLayout(DefinitionsU, sizeToContentU); 
 
                        ValidateDefinitionsVStructure();
                        ValidateDefinitionsLayout(DefinitionsV, sizeToContentV); 

                        CellsStructureDirty |= (SizeToContentU != sizeToContentU) || (SizeToContentV != sizeToContentV);

                        SizeToContentU = sizeToContentU; 
                        SizeToContentV = sizeToContentV;
                    } 
 
                    ValidateCells();
 
                    Debug.Assert(DefinitionsU.Length > 0 && DefinitionsV.Length > 0);

                    //  Grid classifies cells into four groups depending on
                    //  the column / row type a cell belongs to (number corresponds to 
                    //  group number):
                    // 
                    //                   Px      Auto     Star 
                    //               +--------+--------+--------+
                    //               |        |        |        | 
                    //            Px |    1   |    1   |    3   |
                    //               |        |        |        |
                    //               +--------+--------+--------+
                    //               |        |        |        | 
                    //          Auto |    1   |    1   |    3   |
                    //               |        |        |        | 
                    //               +--------+--------+--------+ 
                    //               |        |        |        |
                    //          Star |    4   |    2   |    4   | 
                    //               |        |        |        |
                    //               +--------+--------+--------+
                    //
                    //  The group number indicates the order in which cells are measured. 
                    //  Certain order is necessary to be able to dynamically resolve star
                    //  columns / rows sizes which are used as input for measuring of 
                    //  the cells belonging to them. 
                    //
                    //  However, there are cases when topology of a grid causes cyclical 
                    //  size dependences. For example:
                    //
                    //
                    //                         column width="Auto"      column width="*" 
                    //                      +----------------------+----------------------+
                    //                      |                      |                      | 
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //  row height="Auto"   |                      |      cell 1 2        |
                    //                      |                      |                      |
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      +----------------------+----------------------+ 
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //  row height="*"      |       cell 2 1       |                      |
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      +----------------------+----------------------+ 
                    //
                    //  In order to accurately calculate constraint width for "cell 1 2" 
                    //  (which is the remaining of grid's available width and calculated
                    //  value of Auto column), "cell 2 1" needs to be calculated first,
                    //  as it contributes to the Auto column's calculated value.
                    //  At the same time in order to accurately calculate constraint 
                    //  height for "cell 2 1", "cell 1 2" needs to be calcualted first,
                    //  as it contributes to Auto row height, which is used in the 
                    //  computation of Star row resolved height. 
                    //
                    //  to "break" this cyclical dependency we are making (arbitrary) 
                    //  decision to treat cells like "cell 2 1" as if they appear in Auto
                    //  rows. And then recalculate them one more time when star row
                    //  heights are resolved.
                    // 
                    //  (Or more strictly) the code below implement the following logic:
                    // 
                    //                       +---------+ 
                    //                       |  enter  |
                    //                       +---------+ 
                    //                            |
                    //                            V
                    //                    +----------------+
                    //                    | Measure Group1 | 
                    //                    +----------------+
                    //                            | 
                    //                            V 
                    //                          / - \
                    //                        /       \ 
                    //                  Y   /    Can    \    N
                    //            +--------|   Resolve   |-----------+
                    //            |         \  StarsV?  /            |
                    //            |           \       /              | 
                    //            |             \ - /                |
                    //            V                                  V 
                    //    +----------------+                       / - \ 
                    //    | Resolve StarsV |                     /       \
                    //    +----------------+               Y   /    Can    \    N 
                    //            |                      +----|   Resolve   |------+
                    //            V                      |     \  StarsU?  /       |
                    //    +----------------+             |       \       /         |
                    //    | Measure Group2 |             |         \ - /           | 
                    //    +----------------+             |                         V
                    //            |                      |                 +-----------------+ 
                    //            V                      |                 | Measure Group2' | 
                    //    +----------------+             |                 +-----------------+
                    //    | Resolve StarsU |             |                         | 
                    //    +----------------+             V                         V
                    //            |              +----------------+        +----------------+
                    //            V              | Resolve StarsU |        | Resolve StarsU |
                    //    +----------------+     +----------------+        +----------------+ 
                    //    | Measure Group3 |             |                         |
                    //    +----------------+             V                         V 
                    //            |              +----------------+        +----------------+ 
                    //            |              | Measure Group3 |        | Measure Group3 |
                    //            |              +----------------+        +----------------+ 
                    //            |                      |                         |
                    //            |                      V                         V
                    //            |              +----------------+        +----------------+
                    //            |              | Resolve StarsV |        | Resolve StarsV | 
                    //            |              +----------------+        +----------------+
                    //            |                      |                         | 
                    //            |                      |                         V 
                    //            |                      |                +------------------+
                    //            |                      |                | Measure Group2'' | 
                    //            |                      |                +------------------+
                    //            |                      |                         |
                    //            +----------------------+-------------------------+
                    //                                   | 
                    //                                   V
                    //                           +----------------+ 
                    //                           | Measure Group4 | 
                    //                           +----------------+
                    //                                   | 
                    //                                   V
                    //                               +--------+
                    //                               |  exit  |
                    //                               +--------+ 
                    //
                    //  where: 
                    //  *   all [Measure GroupN] - regular children measure process - 
                    //      each cell is measured given contraint size as an input
                    //      and each cell's desired size is accumulated on the 
                    //      corresponding column / row;
                    //  *   [Measure Group2'] - is when each cell is measured with
                    //      infinit height as a constraint and a cell's desired
                    //      height is ignored; 
                    //  *   [Measure Groups''] - is when each cell is measured (second
                    //      time during single Grid.MeasureOverride) regularly but its 
                    //      returned width is ignored; 
                    //
                    //  This algorithm is believed to be as close to ideal as possible. 
                    //  It has the following drawbacks:
                    //  *   cells belonging to Group2 can be called to measure twice;
                    //  *   iff during second measure a cell belonging to Group2 returns
                    //      desired width greater than desired width returned the first 
                    //      time, such a cell is going to be clipped, even though it
                    //      appears in Auto column. 
                    // 

                    MeasureCellsGroup(extData.CellGroup1, constraint, false, false); 

                    {
                        //  after Group1 is measured,  only Group3 may have cells belonging to Auto rows.
                        bool canResolveStarsV = !HasGroup3CellsInAutoRows; 

                        if (canResolveStarsV) 
                        { 
                            if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); }
                            MeasureCellsGroup(extData.CellGroup2, constraint, false, false); 
                            if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); }
                            MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                        }
                        else 
                        {
                            //  if at least one cell exists in Group2, it must be measured before 
                            //  StarsU can be resolved. 
                            bool canResolveStarsU = extData.CellGroup2 > PrivateCells.Length;
                            if (canResolveStarsU) 
                            {
                                if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); }
                                MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                                if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); } 
                            }
                            else 
                            { 
                                MeasureCellsGroup(extData.CellGroup2, constraint, false, true);
                                if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); } 
                                MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                                if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); }
                                MeasureCellsGroup(extData.CellGroup2, constraint, true, false);
                            } 
                        }
                    } 
 
                    MeasureCellsGroup(extData.CellGroup4, constraint, false, false);
 
                    EnterCounter(Counters._CalculateDesiredSize);
                    gridDesiredSize = new Size(
                            CalculateDesiredSize(DefinitionsU),
                            CalculateDesiredSize(DefinitionsV)); 
                    ExitCounter(Counters._CalculateDesiredSize);
                } 
            } 
            finally
            { 
                MeasureOverrideInProgress = false;
                ExitCounterScope(Counters.MeasureOverride);
            }
 
            return (gridDesiredSize);
        } 
 
        /// 
        /// Content arrangement. 
        /// 
        /// Arrange size
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            try
            { 
                EnterCounterScope(Counters.ArrangeOverride); 

                ArrangeOverrideInProgress = true; 

                if (_data == null)
                {
                    UIElementCollection children = InternalChildren; 

                    for (int i = 0, count = children.Count; i < count; ++i) 
                    { 
                        UIElement child = children[i];
                        if (child != null) 
                        {
                            child.Arrange(new Rect(arrangeSize));
                        }
                    } 
                }
                else 
                { 
                    Debug.Assert(DefinitionsU.Length > 0 && DefinitionsV.Length > 0);
 
                    EnterCounter(Counters._SetFinalSize);

                    SetFinalSize(DefinitionsU, arrangeSize.Width);
                    SetFinalSize(DefinitionsV, arrangeSize.Height); 

                    ExitCounter(Counters._SetFinalSize); 
 
                    UIElementCollection children = InternalChildren;
 
                    for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell)
                    {
                        UIElement cell = children[currentCell];
                        if (cell == null) 
                        {
                            continue; 
                        } 

                        int columnIndex = PrivateCells[currentCell].ColumnIndex; 
                        int rowIndex = PrivateCells[currentCell].RowIndex;
                        int columnSpan = PrivateCells[currentCell].ColumnSpan;
                        int rowSpan = PrivateCells[currentCell].RowSpan;
 
                        Rect cellRect = new Rect(
                            columnIndex == 0 ? 0.0 : DefinitionsU[columnIndex].FinalOffset, 
                            rowIndex == 0 ? 0.0 : DefinitionsV[rowIndex].FinalOffset, 
                            GetFinalSizeForRange(DefinitionsU, columnIndex, columnSpan),
                            GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan)   ); 

                        EnterCounter(Counters._ArrangeChildHelper2);
                        cell.Arrange(cellRect);
                        ExitCounter(Counters._ArrangeChildHelper2); 
                    }
 
                    //  update render bound on grid lines renderer visual 
                    GridLinesRenderer gridLinesRenderer = EnsureGridLinesRenderer();
                    if (gridLinesRenderer != null) 
                    {
                        gridLinesRenderer.UpdateRenderBounds(arrangeSize);
                    }
                } 
            }
            finally 
            { 
                SetValid();
                ArrangeOverrideInProgress = false; 
                ExitCounterScope(Counters.ArrangeOverride);
            }
            return (arrangeSize);
        } 

        ///  
        ///  
        /// 
        protected internal override void OnVisualChildrenChanged( 
            DependencyObject visualAdded,
            DependencyObject visualRemoved)
        {
            CellsStructureDirty = true; 

            base.OnVisualChildrenChanged(visualAdded, visualRemoved); 
        } 

        #endregion Protected Methods 

        //-----------------------------------------------------
        //
        //  Internal Methods 
        //
        //----------------------------------------------------- 
 
        #region Internal Methods
 
        /// 
        ///     Invalidates grid caches and makes the grid dirty for measure.
        /// 
        internal void Invalidate() 
        {
            CellsStructureDirty = true; 
            InvalidateMeasure(); 
        }
 
        /// 
        ///     Returns final width for a column.
        /// 
        ///  
        ///     Used from public ColumnDefinition ActualWidth. Calculates final width using offset data.
        ///  
        internal double GetFinalColumnDefinitionWidth(int columnIndex) 
        {
            double value = 0.0; 

            Invariant.Assert(_data != null);

            //  actual value calculations require structure to be up-to-date 
            if (!ColumnDefinitionCollectionDirty)
            { 
                DefinitionBase[] definitions = DefinitionsU; 
                value = definitions[(columnIndex + 1) % definitions.Length].FinalOffset;
                if (columnIndex != 0) { value -= definitions[columnIndex].FinalOffset; } 
            }
            return (value);
        }
 
        /// 
        ///     Returns final height for a row. 
        ///  
        /// 
        ///     Used from public RowDefinition ActualHeight. Calculates final height using offset data. 
        /// 
        internal double GetFinalRowDefinitionHeight(int rowIndex)
        {
            double value = 0.0; 

            Invariant.Assert(_data != null); 
 
            //  actual value calculations require structure to be up-to-date
            if (!RowDefinitionCollectionDirty) 
            {
                DefinitionBase[] definitions = DefinitionsV;
                value = definitions[(rowIndex + 1) % definitions.Length].FinalOffset;
                if (rowIndex != 0) { value -= definitions[rowIndex].FinalOffset; } 
            }
            return (value); 
        } 

        #endregion Internal Methods 

        //-----------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        /// 
        /// Convenience accessor to MeasureOverrideInProgress bit flag.
        /// 
        internal bool MeasureOverrideInProgress 
        {
            get { return (CheckFlagsAnd(Flags.MeasureOverrideInProgress)); } 
            set { SetFlags(value, Flags.MeasureOverrideInProgress); } 
        }
 
        /// 
        /// Convenience accessor to ArrangeOverrideInProgress bit flag.
        /// 
        internal bool ArrangeOverrideInProgress 
        {
            get { return (CheckFlagsAnd(Flags.ArrangeOverrideInProgress)); } 
            set { SetFlags(value, Flags.ArrangeOverrideInProgress); } 
        }
 
        /// 
        /// Convenience accessor to ValidDefinitionsUStructure bit flag.
        /// 
        internal bool ColumnDefinitionCollectionDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidDefinitionsUStructure)); } 
            set { SetFlags(!value, Flags.ValidDefinitionsUStructure); } 
        }
 
        /// 
        /// Convenience accessor to ValidDefinitionsVStructure bit flag.
        /// 
        internal bool RowDefinitionCollectionDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidDefinitionsVStructure)); } 
            set { SetFlags(!value, Flags.ValidDefinitionsVStructure); } 
        }
 
        #endregion Internal Properties

        //-----------------------------------------------------
        // 
        //  Private Methods
        // 
        //------------------------------------------------------ 

        #region Private Methods 

        /// 
        /// Lays out cells according to rows and columns, and creates lookup grids.
        ///  
        private void ValidateCells()
        { 
            EnterCounter(Counters._ValidateCells); 

            if (CellsStructureDirty) 
            {
                ValidateCellsCore();
                CellsStructureDirty = false;
            } 

            ExitCounter(Counters._ValidateCells); 
        } 

        ///  
        /// ValidateCellsCore
        /// 
        private void ValidateCellsCore()
        { 
            UIElementCollection children = InternalChildren;
            ExtendedData extData = ExtData; 
 
            extData.CellCachesCollection = new CellCache[children.Count];
            extData.CellGroup1 = int.MaxValue; 
            extData.CellGroup2 = int.MaxValue;
            extData.CellGroup3 = int.MaxValue;
            extData.CellGroup4 = int.MaxValue;
 
            bool hasStarCellsU = false;
            bool hasStarCellsV = false; 
            bool hasGroup3CellsInAutoRows = false; 

            for (int i = PrivateCells.Length - 1; i >= 0; --i) 
            {
                UIElement child = children[i];
                if (child == null)
                { 
                    continue;
                } 
 
                CellCache cell = new CellCache();
 
                //
                //  read and cache child positioning properties
                //
 
                //  read indices from the corresponding properties
                //      clamp to value < number_of_columns 
                //      column >= 0 is guaranteed by property value validation callback 
                cell.ColumnIndex = Math.Min(GetColumn(child), DefinitionsU.Length - 1);
                //      clamp to value < number_of_rows 
                //      row >= 0 is guaranteed by property value validation callback
                cell.RowIndex = Math.Min(GetRow(child), DefinitionsV.Length - 1);

                //  read span properties 
                //      clamp to not exceed beyond right side of the grid
                //      column_span > 0 is guaranteed by property value validation callback 
                cell.ColumnSpan = Math.Min(GetColumnSpan(child), DefinitionsU.Length - cell.ColumnIndex); 

                //      clamp to not exceed beyond bottom side of the grid 
                //      row_span > 0 is guaranteed by property value validation callback
                cell.RowSpan = Math.Min(GetRowSpan(child), DefinitionsV.Length - cell.RowIndex);

                Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Length); 
                Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Length);
 
                // 
                //  calculate and cache length types for the child
                // 

                cell.SizeTypeU = GetLengthTypeForRange(DefinitionsU, cell.ColumnIndex, cell.ColumnSpan);
                cell.SizeTypeV = GetLengthTypeForRange(DefinitionsV, cell.RowIndex, cell.RowSpan);
 
                hasStarCellsU |= cell.IsStarU;
                hasStarCellsV |= cell.IsStarV; 
 
                //
                //  distribute cells into four groups. 
                //

                if (!cell.IsStarV)
                { 
                    if (!cell.IsStarU)
                    { 
                        cell.Next = extData.CellGroup1; 
                        extData.CellGroup1 = i;
                    } 
                    else
                    {
                        cell.Next = extData.CellGroup3;
                        extData.CellGroup3 = i; 

                        //  remember if this cell belongs to auto row 
                        hasGroup3CellsInAutoRows |= cell.IsAutoV; 
                    }
                } 
                else
                {
                    if (    cell.IsAutoU
                            //  note below: if spans through Star column it is NOT Auto 
                        &&  !cell.IsStarU )
                    { 
                        cell.Next = extData.CellGroup2; 
                        extData.CellGroup2 = i;
                    } 
                    else
                    {
                        cell.Next = extData.CellGroup4;
                        extData.CellGroup4 = i; 
                    }
                } 
 
                PrivateCells[i] = cell;
            } 

            HasStarCellsU = hasStarCellsU;
            HasStarCellsV = hasStarCellsV;
            HasGroup3CellsInAutoRows = hasGroup3CellsInAutoRows; 
        }
 
        ///  
        /// Initializes DefinitionsU memeber either to user supplied ColumnDefinitions collection
        /// or to a default single element collection. DefinitionsU gets trimmed to size. 
        /// 
        /// 
        /// This is one of two methods, where ColumnDefinitions and DefinitionsU are directly accessed.
        /// All the rest measure / arrange / render code must use DefinitionsU. 
        /// 
        private void ValidateDefinitionsUStructure() 
        { 
            EnterCounter(Counters._ValidateColsStructure);
 
            if (ColumnDefinitionCollectionDirty)
            {
                ExtendedData extData = ExtData;
 
                if (extData.ColumnDefinitions == null)
                { 
                    if (extData.DefinitionsU == null) 
                    {
                        extData.DefinitionsU = new DefinitionBase[] { new ColumnDefinition() }; 
                    }
                }
                else
                { 
                    extData.ColumnDefinitions.InternalTrimToSize();
 
                    if (extData.ColumnDefinitions.InternalCount == 0) 
                    {
                        //  if column definitions collection is empty 
                        //  mockup array with one column
                        extData.DefinitionsU = new DefinitionBase[] { new ColumnDefinition() };
                    }
                    else 
                    {
                        extData.DefinitionsU = extData.ColumnDefinitions.InternalItems; 
                    } 
                }
 
                ColumnDefinitionCollectionDirty = false;
            }

            Debug.Assert(ExtData.DefinitionsU != null && ExtData.DefinitionsU.Length > 0); 

            ExitCounter(Counters._ValidateColsStructure); 
        } 

        ///  
        /// Initializes DefinitionsV memeber either to user supplied RowDefinitions collection
        /// or to a default single element collection. DefinitionsV gets trimmed to size.
        /// 
        ///  
        /// This is one of two methods, where RowDefinitions and DefinitionsV are directly accessed.
        /// All the rest measure / arrange / render code must use DefinitionsV. 
        ///  
        private void ValidateDefinitionsVStructure()
        { 
            EnterCounter(Counters._ValidateRowsStructure);

            if (RowDefinitionCollectionDirty)
            { 
                ExtendedData extData = ExtData;
 
                if (extData.RowDefinitions == null) 
                {
                    if (extData.DefinitionsV == null) 
                    {
                        extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() };
                    }
                } 
                else
                { 
                    extData.RowDefinitions.InternalTrimToSize(); 

                    if (extData.RowDefinitions.InternalCount == 0) 
                    {
                        //  if row definitions collection is empty
                        //  mockup array with one row
                        extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() }; 
                    }
                    else 
                    { 
                        extData.DefinitionsV = extData.RowDefinitions.InternalItems;
                    } 
                }

                RowDefinitionCollectionDirty = false;
            } 

            Debug.Assert(ExtData.DefinitionsV != null && ExtData.DefinitionsV.Length > 0); 
 
            ExitCounter(Counters._ValidateRowsStructure);
        } 

        /// 
        /// Validates layout time size type information on given array of definitions.
        /// Sets MinSize and MeasureSizes. 
        /// 
        /// Array of definitions to update. 
        /// if "true" then star definitions are treated as Auto. 
        private void ValidateDefinitionsLayout(
            DefinitionBase[] definitions, 
            bool treatStarAsAuto)
        {
            for (int i = 0; i < definitions.Length; ++i)
            { 
                definitions[i].OnBeforeLayout(this);
 
                double userMinSize = definitions[i].UserMinSize; 
                double userMaxSize = definitions[i].UserMaxSize;
                double userSize = 0; 

                switch (definitions[i].UserSize.GridUnitType)
                {
                    case (GridUnitType.Pixel): 
                        definitions[i].SizeType = LayoutTimeSizeType.Pixel;
                        userSize = definitions[i].UserSize.Value; 
                        // this was brought with NewLayout and defeats squishy behavior 
                        userMinSize = Math.Max(userMinSize, Math.Min(userSize, userMaxSize));
                        break; 
                    case (GridUnitType.Auto):
                        definitions[i].SizeType = LayoutTimeSizeType.Auto;
                        userSize = double.PositiveInfinity;
                        break; 
                    case (GridUnitType.Star):
                        if (treatStarAsAuto) 
                        { 
                            definitions[i].SizeType = LayoutTimeSizeType.Auto;
                            userSize = double.PositiveInfinity; 
                        }
                        else
                        {
                            definitions[i].SizeType = LayoutTimeSizeType.Star; 
                            userSize = double.PositiveInfinity;
                        } 
                        break; 
                    default:
                        Debug.Assert(false); 
                        break;
                }

                definitions[i].UpdateMinSize(userMinSize); 
                definitions[i].MeasureSize = Math.Max(userMinSize, Math.Min(userSize, userMaxSize));
            } 
        } 

        ///  
        /// Measures one group of cells.
        /// 
        /// Head index of the cells chain.
        /// Reference size for spanned cells 
        /// calculations.
        /// When "true" cells' desired 
        /// width is not registered in columns. 
        /// Passed through to MeasureCell.
        /// When "true" cells' desired height is not registered in rows. 
        private void MeasureCellsGroup(
            int cellsHead,
            Size referenceSize,
            bool ignoreDesiredSizeU, 
            bool forceInfinityV)
        { 
            if (cellsHead >= PrivateCells.Length) 
            {
                return; 
            }

            UIElementCollection children = InternalChildren;
            Hashtable spanStore = null; 
            bool ignoreDesiredSizeV = forceInfinityV;
 
            int i = cellsHead; 
            do
            { 
                MeasureCell(i, forceInfinityV);

                if (!ignoreDesiredSizeU)
                { 
                    if (PrivateCells[i].ColumnSpan == 1)
                    { 
                        DefinitionsU[PrivateCells[i].ColumnIndex].UpdateMinSize(children[i].DesiredSize.Width); 
                    }
                    else 
                    {
                        RegisterSpan(
                            ref spanStore,
                            PrivateCells[i].ColumnIndex, 
                            PrivateCells[i].ColumnSpan,
                            true, 
                            children[i].DesiredSize.Width); 
                    }
                } 

                if (!ignoreDesiredSizeV)
                {
                    if (PrivateCells[i].RowSpan == 1) 
                    {
                        DefinitionsV[PrivateCells[i].RowIndex].UpdateMinSize(children[i].DesiredSize.Height); 
                    } 
                    else
                    { 
                        RegisterSpan(
                            ref spanStore,
                            PrivateCells[i].RowIndex,
                            PrivateCells[i].RowSpan, 
                            false,
                            children[i].DesiredSize.Height); 
                    } 
                }
 
                i = PrivateCells[i].Next;
            } while (i < PrivateCells.Length);

            if (spanStore != null) 
            {
                foreach (DictionaryEntry e in spanStore) 
                { 
                    SpanKey key = (SpanKey)e.Key;
                    double requestedSize = (double)e.Value; 

                    EnsureMinSizeInDefinitionRange(
                        key.U ? DefinitionsU : DefinitionsV,
                        key.Start, 
                        key.Count,
                        requestedSize, 
                        key.U ? referenceSize.Width : referenceSize.Height); 
                }
            } 
        }

        /// 
        /// Helper method to register a span information for delayed processing. 
        /// 
        /// Reference to a hashtable object used as storage. 
        /// Span starting index. 
        /// Span count.
        /// true if this is a column span. false if this is a row span. 
        /// Value to store. If an entry already exists the biggest value is stored.
        private static void RegisterSpan(
            ref Hashtable store,
            int start, 
            int count,
            bool u, 
            double value) 
        {
            if (store == null) 
            {
                store = new Hashtable();
            }
 
            SpanKey key = new SpanKey(start, count, u);
            object o = store[key]; 
 
            if (    o == null
                ||  value > (double)o   ) 
            {
                store[key] = value;
            }
        } 

        ///  
        /// Takes care of measuring a single cell. 
        /// 
        /// Index of the cell to measure. 
        /// If "true" then cell is always
        /// calculated to infinite height.
        private void MeasureCell(
            int cell, 
            bool forceInfinityV)
        { 
            EnterCounter(Counters._MeasureCell); 

            double cellMeasureWidth; 
            double cellMeasureHeight;

            if (    PrivateCells[cell].IsAutoU
                &&  !PrivateCells[cell].IsStarU   ) 
            {
                //  if cell belongs to at least one Auto column and not a single Star column 
                //  then it should be calculated "to content", thus it is possible to "shortcut" 
                //  calculations and simply assign PositiveInfinity here.
                cellMeasureWidth = double.PositiveInfinity; 
            }
            else
            {
                //  otherwise... 
                cellMeasureWidth = GetMeasureSizeForRange(
                                        DefinitionsU, 
                                        PrivateCells[cell].ColumnIndex, 
                                        PrivateCells[cell].ColumnSpan);
            } 

            if (forceInfinityV)
            {
                cellMeasureHeight = double.PositiveInfinity; 
            }
            else if (   PrivateCells[cell].IsAutoV 
                    &&  !PrivateCells[cell].IsStarV   ) 
            {
                //  if cell belongs to at least one Auto row and not a single Star row 
                //  then it should be calculated "to content", thus it is possible to "shortcut"
                //  calculations and simply assign PositiveInfinity here.
                cellMeasureHeight = double.PositiveInfinity;
            } 
            else
            { 
                cellMeasureHeight = GetMeasureSizeForRange( 
                                        DefinitionsV,
                                        PrivateCells[cell].RowIndex, 
                                        PrivateCells[cell].RowSpan);
            }

            EnterCounter(Counters.__MeasureChild); 
            UIElement child = InternalChildren[cell];
            if (child != null) 
            { 
                Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
                Helper.SetMeasureDataOnChild(this, child, childConstraint);  // pass along MeasureData so it continues down the tree. 
                child.Measure(childConstraint);
            }
            ExitCounter(Counters.__MeasureChild);
 
            ExitCounter(Counters._MeasureCell);
        } 
 

        ///  
        /// Calculates one dimensional measure size for given definitions' range.
        /// 
        /// Source array of definitions to read values from.
        /// Starting index of the range. 
        /// Number of definitions included in the range.
        /// Calculated measure size. 
        ///  
        /// For "Auto" definitions MinWidth is used in place of PreferredSize.
        ///  
        private double GetMeasureSizeForRange(
            DefinitionBase[] definitions,
            int start,
            int count) 
        {
            Debug.Assert(0 < count && 0 <= start && (start + count) <= definitions.Length); 
 
            double measureSize = 0;
            int i = start + count - 1; 

            do
            {
                measureSize += (definitions[i].SizeType == LayoutTimeSizeType.Auto) 
                    ? definitions[i].MinSize
                    : definitions[i].MeasureSize; 
            } while (--i >= start); 

            return (measureSize); 
        }

        /// 
        /// Accumulates length type information for given definition's range. 
        /// 
        /// Source array of definitions to read values from. 
        /// Starting index of the range. 
        /// Number of definitions included in the range.
        /// Length type for given range. 
        private LayoutTimeSizeType GetLengthTypeForRange(
            DefinitionBase[] definitions,
            int start,
            int count) 
        {
            Debug.Assert(0 < count && 0 <= start && (start + count) <= definitions.Length); 
 
            LayoutTimeSizeType lengthType = LayoutTimeSizeType.None;
            int i = start + count - 1; 

            do
            {
                lengthType |= definitions[i].SizeType; 
            } while (--i >= start);
 
            return (lengthType); 
        }
 
        /// 
        /// Distributes min size back to definition array's range.
        /// 
        /// Start of the range. 
        /// Number of items in the range.
        /// Minimum size that should "fit" into the definitions range. 
        /// Definition array receiving distribution. 
        /// Size used to resolve percentages.
        private void EnsureMinSizeInDefinitionRange( 
            DefinitionBase[] definitions,
            int start,
            int count,
            double requestedSize, 
            double percentReferenceSize)
        { 
            Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Length); 

            //  avoid processing when asked to distribute "0" 
            if (!_IsZero(requestedSize))
            {
                DefinitionBase[] tempDefinitions = TempDefinitions; //  temp array used to remember definitions for sorting
                int end = start + count; 
                int autoDefinitionsCount = 0;
                double rangeMinSize = 0; 
                double rangePreferredSize = 0; 
                double rangeMaxSize = 0;
                double maxMaxSize = 0;                              //  maximum of maximum sizes 

                //  first accumulate the necessary information:
                //  a) sum up the sizes in the range;
                //  b) count the number of auto definitions in the range; 
                //  c) initialize temp array
                //  d) cache the maximum size into SizeCache 
                //  e) accumulate max of max sizes 
                for (int i = start; i < end; ++i)
                { 
                    double minSize = definitions[i].MinSize;
                    double preferredSize = definitions[i].PreferredSize;
                    double maxSize = Math.Max(definitions[i].UserMaxSize, minSize);
 
                    rangeMinSize += minSize;
                    rangePreferredSize += preferredSize; 
                    rangeMaxSize += maxSize; 

                    definitions[i].SizeCache = maxSize; 

                    //  sanity check: no matter what, but min size must always be the smaller;
                    //  max size must be the biggest; and preferred should be in between
                    Debug.Assert(   minSize <= preferredSize 
                                &&  preferredSize <= maxSize
                                &&  rangeMinSize <= rangePreferredSize 
                                &&  rangePreferredSize <= rangeMaxSize  ); 

                    if (maxMaxSize < maxSize)   maxMaxSize = maxSize; 
                    if (definitions[i].UserSize.IsAuto) autoDefinitionsCount++;
                    tempDefinitions[i - start] = definitions[i];
                }
 
                //  avoid processing if the range already big enough
                if (requestedSize > rangeMinSize) 
                { 
                    if (requestedSize <= rangePreferredSize)
                    { 
                        //
                        //  requestedSize fits into preferred size of the range.
                        //  distribute according to the following logic:
                        //  * do not distribute into auto definitions - they should continue to stay "tight"; 
                        //  * for all non-auto definitions distribute to equi-size min sizes, without exceeding preferred size.
                        // 
                        //  in order to achieve that, definitions are sorted in a way that all auto definitions 
                        //  are first, then definitions follow ascending order with PreferredSize as the key of sorting.
                        // 
                        double sizeToDistribute;
                        int i;

                        Array.Sort(tempDefinitions, 0, count, s_spanPreferredDistributionOrderComparer); 
                        for (i = 0, sizeToDistribute = requestedSize; i < autoDefinitionsCount; ++i)
                        { 
                            //  sanity check: only auto definitions allowed in this loop 
                            Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
 
                            //  adjust sizeToDistribute value by subtracting auto definition min size
                            sizeToDistribute -= (tempDefinitions[i].MinSize);
                        }
 
                        for (; i < count; ++i)
                        { 
                            //  sanity check: no auto definitions allowed in this loop 
                            Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
 
                            double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinitions[i].PreferredSize);
                            if (newMinSize > tempDefinitions[i].MinSize) { tempDefinitions[i].UpdateMinSize(newMinSize); }
                            sizeToDistribute -= newMinSize;
                        } 

                        //  sanity check: requested size must all be distributed 
                        Debug.Assert(_IsZero(sizeToDistribute)); 
                    }
                    else if (requestedSize <= rangeMaxSize) 
                    {
                        //
                        //  requestedSize bigger than preferred size, but fit into max size of the range.
                        //  distribute according to the following logic: 
                        //  * do not distribute into auto definitions, if possible - they should continue to stay "tight";
                        //  * for all non-auto definitions distribute to euqi-size min sizes, without exceeding max size. 
                        // 
                        //  in order to achieve that, definitions are sorted in a way that all non-auto definitions
                        //  are last, then definitions follow ascending order with MaxSize as the key of sorting. 
                        //
                        double sizeToDistribute;
                        int i;
 
                        Array.Sort(tempDefinitions, 0, count, s_spanMaxDistributionOrderComparer);
                        for (i = 0, sizeToDistribute = requestedSize - rangePreferredSize; i < count - autoDefinitionsCount; ++i) 
                        { 
                            //  sanity check: no auto definitions allowed in this loop
                            Debug.Assert(!tempDefinitions[i].UserSize.IsAuto); 

                            double preferredSize = tempDefinitions[i].PreferredSize;
                            double newMinSize = preferredSize + sizeToDistribute / (count - autoDefinitionsCount - i);
                            tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache)); 
                            sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
                        } 
 
                        for (; i < count; ++i)
                        { 
                            //  sanity check: only auto definitions allowed in this loop
                            Debug.Assert(tempDefinitions[i].UserSize.IsAuto);

                            double preferredSize = tempDefinitions[i].MinSize; 
                            double newMinSize = preferredSize + sizeToDistribute / (count - i);
                            tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache)); 
                            sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize); 
                        }
 
                        //  sanity check: requested size must all be distributed
                        Debug.Assert(_IsZero(sizeToDistribute));
                    }
                    else 
                    {
                        // 
                        //  requestedSize bigger than max size of the range. 
                        //  distribute according to the following logic:
                        //  * for all definitions distribute to equi-size min sizes. 
                        //
                        double equalSize = requestedSize / count;

                        if (    equalSize < maxMaxSize 
                            &&  !_AreClose(equalSize, maxMaxSize)   )
                        { 
                            //  equi-size is less than maximum of maxSizes. 
                            //  in this case distribute so that smaller definitions grow faster than
                            //  bigger ones. 
                            double totalRemainingSize = maxMaxSize * count - rangeMaxSize;
                            double sizeToDistribute = requestedSize - rangeMaxSize;

                            //  sanity check: totalRemainingSize and sizeToDistribute must be real positive numbers 
                            Debug.Assert(   !double.IsInfinity(totalRemainingSize)
                                        &&  !DoubleUtil.IsNaN(totalRemainingSize) 
                                        &&  totalRemainingSize > 0 
                                        &&  !double.IsInfinity(sizeToDistribute)
                                        &&  !DoubleUtil.IsNaN(sizeToDistribute) 
                                        &&  sizeToDistribute > 0    );

                            for (int i = 0; i < count; ++i)
                            { 
                                double deltaSize = (maxMaxSize - tempDefinitions[i].SizeCache) * sizeToDistribute / totalRemainingSize;
                                tempDefinitions[i].UpdateMinSize(tempDefinitions[i].SizeCache + deltaSize); 
                            } 
                        }
                        else 
                        {
                            //
                            //  equi-size is greater or equal to maximum of max sizes.
                            //  all definitions receive equalSize as their mim sizes. 
                            //
                            for (int i = 0; i < count; ++i) 
                            { 
                                tempDefinitions[i].UpdateMinSize(equalSize);
                            } 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// Resolves Star's for given array of definitions.
        ///  
        /// Array of definitions to resolve stars.
        /// All available size.
        /// 
        /// Must initialize LayoutSize for all Star entries in given array of definitions. 
        /// 
        private void ResolveStar( 
            DefinitionBase[] definitions, 
            double availableSize)
        { 
            DefinitionBase[] tempDefinitions = TempDefinitions;
            int starDefinitionsCount = 0;
            double takenSize = 0;
 
            for (int i = 0; i < definitions.Length; ++i)
            { 
                switch (definitions[i].SizeType) 
                {
                    case (LayoutTimeSizeType.Auto): 
                        takenSize += definitions[i].MinSize;
                        break;
                    case (LayoutTimeSizeType.Pixel):
                        takenSize += definitions[i].MeasureSize; 
                        break;
                    case (LayoutTimeSizeType.Star): 
                        { 
                            tempDefinitions[starDefinitionsCount++] = definitions[i];
 
                            double starValue = definitions[i].UserSize.Value;

                            if (_IsZero(starValue))
                            { 
                                definitions[i].MeasureSize = 0;
                                definitions[i].SizeCache = 0; 
                            } 
                            else
                            { 
                                //  clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values
                                //  can be summed up without overflow
                                starValue = Math.Min(starValue, c_starClip);
 
                                //  Note: normalized star value is temporary cached into MeasureSize
                                definitions[i].MeasureSize = starValue; 
                                double maxSize             = Math.Max(definitions[i].MinSize, definitions[i].UserMaxSize); 
                                maxSize                    = Math.Min(maxSize, c_starClip);
                                definitions[i].SizeCache   = maxSize / starValue; 
                            }
                        }
                        break;
                } 
            }
 
            if (starDefinitionsCount > 0) 
            {
                Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer); 

                //  the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow...
                //  partial sum value is stored in each definition's SizeCache member.
                //  this way the algorithm guarantees (starValue <= definition.SizeCache) and thus 
                //  (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero.
                //  this is an important change from previous implementation where the following was possible: 
                //  ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... 
                double allStarWeights = 0;
                int i = starDefinitionsCount - 1; 
                do
                {
                    allStarWeights += tempDefinitions[i].MeasureSize;
                    tempDefinitions[i].SizeCache = allStarWeights; 
                } while (--i >= 0);
 
                i = 0; 
                do
                { 
                    double resolvedSize;
                    double starValue = tempDefinitions[i].MeasureSize;

                    if (_IsZero(starValue)) 
                    {
                        resolvedSize = tempDefinitions[i].MinSize; 
                    } 
                    else
                    { 
                        double userSize = Math.Max(availableSize - takenSize, 0.0) * (starValue / tempDefinitions[i].SizeCache);
                        resolvedSize    = Math.Min(userSize, tempDefinitions[i].UserMaxSize);
                        resolvedSize    = Math.Max(tempDefinitions[i].MinSize, resolvedSize);
                    } 

                    tempDefinitions[i].MeasureSize = resolvedSize; 
                    takenSize                     += resolvedSize; 
                } while (++i < starDefinitionsCount);
            } 
        }

        /// 
        /// Calculates desired size for given array of definitions. 
        /// 
        /// Array of definitions to use for calculations. 
        /// Desired size. 
        private double CalculateDesiredSize(
            DefinitionBase[] definitions) 
        {
            double desiredSize = 0;

            for (int i = 0; i < definitions.Length; ++i) 
            {
                desiredSize += definitions[i].MinSize; 
            } 

            return (desiredSize); 
        }

        /// 
        /// Calculates and sets final size for all definitions in the given array. 
        /// 
        /// Array of definitions to process. 
        /// Final size to lay out to. 
        private void SetFinalSize(
            DefinitionBase[] definitions, 
            double finalSize)
        {
            DefinitionBase[] tempDefinitions = TempDefinitions; //  temp array used to remember definitions indices
            int starDefinitionsCount = 0;                       //  traverses form the first entry up 
            int nonStarIndex = definitions.Length;              //  traverses from the last entry down
            double allPreferredArrangeSize = 0; 
 
            for (int i = 0; i < definitions.Length; ++i)
            { 
                //  if definition is shared then is cannot be star
                Debug.Assert(!definitions[i].IsShared || !definitions[i].UserSize.IsStar);

                if (definitions[i].UserSize.IsStar) 
                {
                    tempDefinitions[starDefinitionsCount++] = definitions[i]; 
 
                    double starValue = definitions[i].UserSize.Value;
 
                    if (_IsZero(starValue))
                    {
                        //  cach normilized star value temporary into MeasureSize
                        definitions[i].MeasureSize = 0; 
                        definitions[i].SizeCache = 0;
                    } 
                    else 
                    {
                        //  clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values 
                        //  can be summed up without overflow
                        starValue = Math.Min(starValue, c_starClip);

                        //  Note: normalized star value is temporary cached into MeasureSize 
                        definitions[i].MeasureSize = starValue;
                        double maxSize = Math.Max(definitions[i].MinSizeForArrange, definitions[i].UserMaxSize); 
                        maxSize = Math.Min(maxSize, c_starClip); 
                        definitions[i].SizeCache = maxSize / starValue;
                    } 
                }
                else
                {
                    tempDefinitions[--nonStarIndex] = definitions[i]; 

                    double userSize = 0; 
 
                    switch (definitions[i].UserSize.GridUnitType)
                    { 
                        case (GridUnitType.Pixel):
                            userSize = definitions[i].UserSize.Value;
                            break;
 
                        case (GridUnitType.Auto):
                            userSize = definitions[i].MinSizeForArrange; 
                            break; 
                    }
 
                    double userMaxSize;

                    if (definitions[i].IsShared)
                    { 
                        //  overriding userMaxSize effectively prevents squishy-ness.
                        //  this is a "solution" to avoid shared definitions from been sized to 
                        //  different final size at arrange time, if / when different grids receive 
                        //  different final sizes.
                        userMaxSize = userSize; 
                    }
                    else
                    {
                        userMaxSize = definitions[i].UserMaxSize; 
                    }
 
                    definitions[i].SizeCache = Math.Max(definitions[i].MinSizeForArrange, Math.Min(userSize, userMaxSize)); 
                    allPreferredArrangeSize += definitions[i].SizeCache;
                } 
            }

            //  indices should meet
            Debug.Assert(nonStarIndex == starDefinitionsCount); 

            if (starDefinitionsCount > 0) 
            { 
                Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer);
 
                //  the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow...
                //  partial sum value is stored in each definition's SizeCache member.
                //  this way the algorithm guarantees (starValue <= definition.SizeCache) and thus
                //  (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. 
                //  this is an important change from previous implementation where the following was possible:
                //  ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... 
                double allStarWeights = 0; 
                int i = starDefinitionsCount - 1;
                do 
                {
                    allStarWeights += tempDefinitions[i].MeasureSize;
                    tempDefinitions[i].SizeCache = allStarWeights;
                } while (--i >= 0); 

                i = 0; 
                do 
                {
                    double resolvedSize; 
                    double starValue = tempDefinitions[i].MeasureSize;

                    if (_IsZero(starValue))
                    { 
                        resolvedSize = tempDefinitions[i].MinSizeForArrange;
                    } 
                    else 
                    {
                        double userSize = Math.Max(finalSize - allPreferredArrangeSize, 0.0) * (starValue / tempDefinitions[i].SizeCache); 
                        resolvedSize    = Math.Min(userSize, tempDefinitions[i].UserMaxSize);
                        resolvedSize    = Math.Max(tempDefinitions[i].MinSizeForArrange, resolvedSize);
                    }
 
                    tempDefinitions[i].SizeCache = resolvedSize;
                    allPreferredArrangeSize     += resolvedSize; 
                } while (++i < starDefinitionsCount); 
            }
 
            if (    allPreferredArrangeSize > finalSize
                &&  !_AreClose(allPreferredArrangeSize, finalSize)  )
            {
                Array.Sort(tempDefinitions, 0, definitions.Length, s_distributionOrderComparer); 
                double sizeToDistribute = finalSize - allPreferredArrangeSize;
 
                for (int i = 0; i < definitions.Length; ++i) 
                {
                    double final = tempDefinitions[i].SizeCache + (sizeToDistribute / (definitions.Length - i)); 

                    final = Math.Max(final, tempDefinitions[i].MinSizeForArrange);
                    final = Math.Min(final, tempDefinitions[i].SizeCache);
                    sizeToDistribute -= (final - tempDefinitions[i].SizeCache); 
                    tempDefinitions[i].SizeCache = final;
                } 
            } 

            definitions[0].FinalOffset = 0.0; 
            for (int i = 0; i < definitions.Length; ++i)
            {
                definitions[(i + 1) % definitions.Length].FinalOffset = definitions[i].FinalOffset + definitions[i].SizeCache;
            } 
        }
 
        ///  
        /// Calculates final (aka arrange) size for given range.
        ///  
        /// Array of definitions to process.
        /// Start of the range.
        /// Number of items in the range.
        /// Final size. 
        private double GetFinalSizeForRange(
            DefinitionBase[] definitions, 
            int start, 
            int count)
        { 
            double size = 0;
            int i = start + count - 1;

            do 
            {
                size += definitions[i].SizeCache; 
            } while (--i >= start); 

            return (size); 
        }

        /// 
        /// Clears dirty state for the grid and its columns / rows 
        /// 
        private void SetValid() 
        { 
            ExtendedData extData = ExtData;
            if (extData != null) 
            {
//                for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid ();
//                for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid ();
 
                if (extData.TempDefinitions != null)
                { 
                    //  TempDefinitions has to be cleared to avoid "memory leaks" 
                    Array.Clear(extData.TempDefinitions, 0, Math.Max(DefinitionsU.Length, DefinitionsV.Length));
                    extData.TempDefinitions = null; 
                }
            }
        }
 
        /// 
        /// Returns true if ColumnDefinitions collection is not empty 
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeColumnDefinitions() 
        {
            ExtendedData extData = ExtData;
            return (    extData != null
                    &&  extData.ColumnDefinitions != null 
                    &&  extData.ColumnDefinitions.Count > 0   );
        } 
 
        /// 
        /// Returns true if RowDefinitions collection is not empty 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeRowDefinitions()
        { 
            ExtendedData extData = ExtData;
            return (    extData != null 
                    &&  extData.RowDefinitions != null 
                    &&  extData.RowDefinitions.Count > 0  );
        } 

        /// 
        /// Synchronized ShowGridLines property with the state of the grid's visual collection
        /// by adding / removing GridLinesRenderer visual. 
        /// Returns a reference to GridLinesRenderer visual or null.
        ///  
        private GridLinesRenderer EnsureGridLinesRenderer() 
        {
            // 
            //  synchronize the state
            //
            if (ShowGridLines && (_gridLinesRenderer == null))
            { 
                _gridLinesRenderer = new GridLinesRenderer();
                this.AddVisualChild(_gridLinesRenderer); 
            } 

            if ((!ShowGridLines) && (_gridLinesRenderer != null)) 
            {
                this.RemoveVisualChild(_gridLinesRenderer);
                _gridLinesRenderer = null;
            } 

            return (_gridLinesRenderer); 
        } 

        ///  
        /// SetFlags is used to set or unset one or multiple
        /// flags on the object.
        /// 
        private void SetFlags(bool value, Flags flags) 
        {
            _flags = value ? (_flags | flags) : (_flags & (~flags)); 
        } 

        ///  
        /// CheckFlagsAnd returns true if all the flags in the
        /// given bitmask are set on the object.
        /// 
        private bool CheckFlagsAnd(Flags flags) 
        {
            return ((_flags & flags) == flags); 
        } 

        ///  
        /// CheckFlagsOr returns true if at least one flag in the
        /// given bitmask is set.
        /// 
        ///  
        /// If no bits are set in the given bitmask, the method returns
        /// true. 
        ///  
        private bool CheckFlagsOr(Flags flags)
        { 
            return (flags == 0 || (_flags & flags) != 0);
        }

        ///  
        /// 
        ///  
        private static void OnShowGridLinesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Grid grid = (Grid)d; 

            if (    grid.ExtData != null    // trivial grid is 1 by 1. there is no grid lines anyway
                &&  grid.ListenToNotifications)
            { 
                grid.InvalidateVisual();
            } 
 
            grid.SetFlags((bool) e.NewValue, Flags.ShowGridLinesPropertyValue);
        } 

        /// 
        /// 
        ///  
        private static void OnCellAttachedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Visual child = d as Visual; 

            if (child != null) 
            {
                Grid grid = VisualTreeHelper.GetParent(child) as Grid;
                if (    grid != null
                    &&  grid.ExtData != null 
                    &&  grid.ListenToNotifications  )
                { 
                    grid.CellsStructureDirty = true; 
                    grid.InvalidateMeasure();
                } 
            }
        }

        ///  
        /// 
        ///  
        private static bool IsIntValueNotNegative(object value) 
        {
            return ((int)value >= 0); 
        }

        /// 
        ///  
        /// 
        private static bool IsIntValueGreaterThanZero(object value) 
        { 
            return ((int)value > 0);
        } 

        #endregion Private Methods

        //------------------------------------------------------ 
        //
        //  Private Properties 
        // 
        //-----------------------------------------------------
 
        #region Private Properties

        /// 
        /// Private version returning array of column definitions. 
        /// 
        private DefinitionBase[] DefinitionsU 
        { 
            get { return (ExtData.DefinitionsU); }
        } 

        /// 
        /// Private version returning array of row definitions.
        ///  
        private DefinitionBase[] DefinitionsV
        { 
            get { return (ExtData.DefinitionsV); } 
        }
 
        /// 
        /// Helper accessor to layout time array of definitions.
        /// 
        private DefinitionBase[] TempDefinitions 
        {
            get 
            { 
                ExtendedData extData = ExtData;
 
                if (extData.TempDefinitions == null)
                {
                    int requiredLength = Math.Max(DefinitionsU.Length, DefinitionsV.Length);
                    WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot); 
                    if (tempDefinitionsWeakRef == null)
                    { 
                        extData.TempDefinitions = new DefinitionBase[requiredLength * 2]; 
                        Thread.SetData(s_tempDefinitionsDataSlot, new WeakReference(extData.TempDefinitions));
                    } 
                    else
                    {
                        extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target;
                        if (    extData.TempDefinitions == null 
                            ||  extData.TempDefinitions.Length < requiredLength   )
                        { 
                            extData.TempDefinitions = new DefinitionBase[requiredLength * 2]; 
                            tempDefinitionsWeakRef.Target = extData.TempDefinitions;
                        } 
                    }
                }
                return (extData.TempDefinitions);
            } 
        }
 
        ///  
        /// Private version returning array of cells.
        ///  
        private CellCache[] PrivateCells
        {
            get { return (ExtData.CellCachesCollection); }
        } 

        ///  
        /// Convenience accessor to ValidCellsStructure bit flag. 
        /// 
        private bool CellsStructureDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidCellsStructure)); }
            set { SetFlags(!value, Flags.ValidCellsStructure); }
        } 

        ///  
        /// Convenience accessor to ListenToNotifications bit flag. 
        /// 
        private bool ListenToNotifications 
        {
            get { return (CheckFlagsAnd(Flags.ListenToNotifications)); }
            set { SetFlags(value, Flags.ListenToNotifications); }
        } 

        ///  
        /// Convenience accessor to SizeToContentU bit flag. 
        /// 
        private bool SizeToContentU 
        {
            get { return (CheckFlagsAnd(Flags.SizeToContentU)); }
            set { SetFlags(value, Flags.SizeToContentU); }
        } 

        ///  
        /// Convenience accessor to SizeToContentV bit flag. 
        /// 
        private bool SizeToContentV 
        {
            get { return (CheckFlagsAnd(Flags.SizeToContentV)); }
            set { SetFlags(value, Flags.SizeToContentV); }
        } 

        ///  
        /// Convenience accessor to HasStarCellsU bit flag. 
        /// 
        private bool HasStarCellsU 
        {
            get { return (CheckFlagsAnd(Flags.HasStarCellsU)); }
            set { SetFlags(value, Flags.HasStarCellsU); }
        } 

        ///  
        /// Convenience accessor to HasStarCellsV bit flag. 
        /// 
        private bool HasStarCellsV 
        {
            get { return (CheckFlagsAnd(Flags.HasStarCellsV)); }
            set { SetFlags(value, Flags.HasStarCellsV); }
        } 

        ///  
        /// Convenience accessor to HasGroup3CellsInAutoRows bit flag. 
        /// 
        private bool HasGroup3CellsInAutoRows 
        {
            get { return (CheckFlagsAnd(Flags.HasGroup3CellsInAutoRows)); }
            set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
        } 

        ///  
        /// fp version of d == 0. 
        /// 
        /// Value to check. 
        /// true if d == 0.
        private static bool _IsZero(double d)
        {
            return (Math.Abs(d) < c_epsilon); 
        }
 
        ///  
        /// fp version of d1 == d2
        ///  
        /// First value to compare
        /// Second value to compare
        /// true if d1 == d2
        private static bool _AreClose(double d1, double d2) 
        {
            return (Math.Abs(d1 - d2) < c_epsilon); 
        } 

        ///  
        /// Returns reference to extended data bag.
        /// 
        private ExtendedData ExtData
        { 
            get { return (_data); }
        } 
 
        #endregion Private Properties
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 
        private ExtendedData _data;                             //  extended data instantiated on demand, for non-trivial case handling only
        private Flags _flags;                                   //  grid validity / property caches dirtiness flags 
        private GridLinesRenderer _gridLinesRenderer;
        #endregion Private Fields

        //----------------------------------------------------- 
        //
        //  Static Fields 
        // 
        //-----------------------------------------------------
 
        #region Static Fields
        private const double c_epsilon = 1e-5;                  //  used in fp calculations
        private const double c_starClip = 1e298;                //  used as maximum for clipping star values during normalization
        private static readonly LocalDataStoreSlot s_tempDefinitionsDataSlot = Thread.AllocateDataSlot(); 
        private static readonly IComparer s_spanPreferredDistributionOrderComparer = new SpanPreferredDistributionOrderComparer();
        private static readonly IComparer s_spanMaxDistributionOrderComparer = new SpanMaxDistributionOrderComparer(); 
        private static readonly IComparer s_starDistributionOrderComparer = new StarDistributionOrderComparer(); 
        private static readonly IComparer s_distributionOrderComparer = new DistributionOrderComparer();
        #endregion Static Fields 

        //------------------------------------------------------
        //
        //  Private Structures / Classes 
        //
        //----------------------------------------------------- 
 
        #region Private Structures Classes
 
        /// 
        /// Extended data instantiated on demand, when grid handles non-trivial case.
        /// 
        private class ExtendedData 
        {
            internal ColumnDefinitionCollection ColumnDefinitions;  //  collection of column definitions (logical tree support) 
            internal RowDefinitionCollection RowDefinitions;        //  collection of row definitions (logical tree support) 
            internal DefinitionBase[] DefinitionsU;                 //  collection of column definitions used during calc
            internal DefinitionBase[] DefinitionsV;                 //  collection of row definitions used during calc 
            internal CellCache[] CellCachesCollection;              //  backing store for logical children
            internal int CellGroup1;                                //  index of the first cell in first cell group
            internal int CellGroup2;                                //  index of the first cell in second cell group
            internal int CellGroup3;                                //  index of the first cell in third cell group 
            internal int CellGroup4;                                //  index of the first cell in forth cell group
            internal DefinitionBase[] TempDefinitions;              //  temporary array used during layout for various purposes 
                                                                    //  TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length) 
        }
 
        /// 
        /// Grid validity / property caches dirtiness flags
        /// 
        [System.Flags] 
        private enum Flags
        { 
            // 
            //  the foolowing flags let grid tracking dirtiness in more granular manner:
            //  * Valid???Structure flags indicate that elements were added or removed. 
            //  * Valid???Layout flags indicate that layout time portion of the information
            //    stored on the objects should be updated.
            //
            ValidDefinitionsUStructure              = 0x00000001, 
            ValidDefinitionsVStructure              = 0x00000002,
            ValidCellsStructure                     = 0x00000004, 
 
            //
            //  boolean properties state 
            //
            ShowGridLinesPropertyValue              = 0x00000100,   //  show grid lines ?

            // 
            //  boolean flags
            // 
            ListenToNotifications                   = 0x00001000,   //  "0" when all notifications are ignored 
            SizeToContentU                          = 0x00002000,   //  "1" if calculating to content in U direction
            SizeToContentV                          = 0x00004000,   //  "1" if calculating to content in V direction 
            HasStarCellsU                           = 0x00008000,   //  "1" if at least one cell belongs to a Star column
            HasStarCellsV                           = 0x00010000,   //  "1" if at least one cell belongs to a Star row
            HasGroup3CellsInAutoRows                = 0x00020000,   //  "1" if at least one cell of group 3 belongs to an Auto row
            MeasureOverrideInProgress               = 0x00040000,   //  "1" while in the context of Grid.MeasureOverride 
            ArrangeOverrideInProgress               = 0x00080000,   //  "1" while in the context of Grid.ArrangeOverride
        } 
 
        #endregion Private Structures Classes
 
        //------------------------------------------------------
        //
        //  Properties
        // 
        //------------------------------------------------------
 
        #region Properties 

        ///  
        /// ShowGridLines property. This property is used mostly
        /// for simplification of visual debuggig. When it is set
        /// to true grid lines are drawn to visualize location
        /// of grid lines. 
        /// 
        public static readonly DependencyProperty ShowGridLinesProperty = 
                DependencyProperty.Register( 
                      "ShowGridLines",
                      typeof(bool), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              false,
                              new PropertyChangedCallback(OnShowGridLinesPropertyChanged))); 

        ///  
        /// Column property. This is an attached property. 
        /// Grid defines Column property, so that it can be set
        /// on any element treated as a cell. Column property 
        /// specifies child's position with respect to columns.
        /// 
        /// 
        ///  Columns are 0 - based. In order to appear in first column, element 
        /// should have Column property set to 0. 
        ///  Default value for the property is 0.  
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty ColumnProperty = 
                DependencyProperty.RegisterAttached(
                      "Column",
                      typeof(int),
                      typeof(Grid), 
                      new FrameworkPropertyMetadata(
                              0, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)), 
                      new ValidateValueCallback(IsIntValueNotNegative));
 
        /// 
        /// Row property. This is an attached property.
        /// Grid defines Row, so that it can be set
        /// on any element treated as a cell. Row property 
        /// specifies child's position with respect to rows.
        ///  
        ///  Rows are 0 - based. In order to appear in first row, element 
        /// should have Row property set to 0. 
        ///  Default value for the property is 0.  
        /// 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty RowProperty = 
                DependencyProperty.RegisterAttached(
                      "Row", 
                      typeof(int), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata( 
                              0,
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueNotNegative));
 
        /// 
        /// ColumnSpan property. This is an attached property. 
        /// Grid defines ColumnSpan, so that it can be set 
        /// on any element treated as a cell. ColumnSpan property
        /// specifies child's width with respect to columns. 
        /// Example, ColumnSpan == 2 means that child will span across two columns.
        /// 
        /// 
        /// Default value for the property is 1. 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ColumnSpanProperty = 
                DependencyProperty.RegisterAttached(
                      "ColumnSpan", 
                      typeof(int),
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              1, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueGreaterThanZero)); 
 
        /// 
        /// RowSpan property. This is an attached property. 
        /// Grid defines RowSpan, so that it can be set
        /// on any element treated as a cell. RowSpan property
        /// specifies child's height with respect to row grid lines.
        /// Example, RowSpan == 3 means that child will span across three rows. 
        /// 
        ///  
        /// Default value for the property is 1. 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty RowSpanProperty =
                DependencyProperty.RegisterAttached(
                      "RowSpan",
                      typeof(int), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata( 
                              1, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueGreaterThanZero)); 


        /// 
        /// IsSharedSizeScope property marks scoping element for shared size. 
        /// 
        public static readonly DependencyProperty IsSharedSizeScopeProperty  = 
                DependencyProperty.RegisterAttached( 
                      "IsSharedSizeScope",
                      typeof(bool), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              false,
                              new PropertyChangedCallback(DefinitionBase.OnIsSharedSizeScopePropertyChanged))); 

        #endregion Properties 
 
        //-----------------------------------------------------
        // 
        //  Internal Structures / Classes
        //
        //------------------------------------------------------
 
        #region Internal Structures Classes
 
        ///  
        /// LayoutTimeSizeType is used internally and reflects layout-time size type.
        ///  
        [System.Flags]
        internal enum LayoutTimeSizeType : byte
        {
            None        = 0x00, 
            Pixel       = 0x01,
            Auto        = 0x02, 
            Star        = 0x04, 
        }
 
        #endregion Internal Structures Classes

        //-----------------------------------------------------
        // 
        //  Private Structures / Classes
        // 
        //----------------------------------------------------- 

        #region Private Structures Classes 

        /// 
        /// CellCache stored calculated values of
        /// 1. attached cell positioning properties; 
        /// 2. size type;
        /// 3. index of a next cell in the group; 
        ///  
        private struct CellCache
        { 
            internal int ColumnIndex;
            internal int RowIndex;
            internal int ColumnSpan;
            internal int RowSpan; 
            internal LayoutTimeSizeType SizeTypeU;
            internal LayoutTimeSizeType SizeTypeV; 
            internal int Next; 
            internal bool IsStarU { get { return ((SizeTypeU & LayoutTimeSizeType.Star) != 0); } }
            internal bool IsAutoU { get { return ((SizeTypeU & LayoutTimeSizeType.Auto) != 0); } } 
            internal bool IsStarV { get { return ((SizeTypeV & LayoutTimeSizeType.Star) != 0); } }
            internal bool IsAutoV { get { return ((SizeTypeV & LayoutTimeSizeType.Auto) != 0); } }
        }
 
        /// 
        /// Helper class for representing a key for a span in hashtable. 
        ///  
        private class SpanKey
        { 
            /// 
            /// Constructor.
            /// 
            /// Starting index of the span. 
            /// Span count.
            /// true for columns; false for rows. 
            internal SpanKey(int start, int count, bool u) 
            {
                _start = start; 
                _count = count;
                _u = u;
            }
 
            /// 
            ///  
            ///  
            public override int GetHashCode()
            { 
                int hash = (_start ^ (_count << 2));

                if (_u) hash &= 0x7ffffff;
                else    hash |= 0x8000000; 

                return (hash); 
            } 

            ///  
            /// 
            /// 
            public override bool Equals(object obj)
            { 
                SpanKey sk = obj as SpanKey;
                return (    sk != null 
                        &&  sk._start == _start 
                        &&  sk._count == _count
                        &&  sk._u == _u ); 
            }

            /// 
            /// Returns start index of the span. 
            /// 
            internal int Start { get { return (_start); } } 
 
            /// 
            /// Returns span count. 
            /// 
            internal int Count { get { return (_count); } }

            ///  
            /// Returns true if this is a column span.
            /// false if this is a row span. 
            ///  
            internal bool U { get { return (_u); } }
 
            private int _start;
            private int _count;
            private bool _u;
        } 

        ///  
        /// SpanPreferredDistributionOrderComparer. 
        /// 
        private class SpanPreferredDistributionOrderComparer : IComparer 
        {
            public int Compare(object x, object y)
            {
                if (x == y) return (0); 

                DefinitionBase definitionX = (DefinitionBase)x; 
                DefinitionBase definitionY = (DefinitionBase)y; 

                if (definitionX.UserSize.IsAuto) 
                {
                    if (definitionY.UserSize.IsAuto)    return ((definitionX.MinSize > definitionY.MinSize) ? 1 : -1);
                    return (-1);
                } 
                else
                { 
                    if (!definitionY.UserSize.IsAuto)   return ((definitionX.PreferredSize > definitionY.PreferredSize) ? 1 : -1); 
                    return (1);
                } 
            }
        }

        ///  
        /// SpanMaxDistributionOrderComparer.
        ///  
        private class SpanMaxDistributionOrderComparer : IComparer 
        {
            public int Compare(object x, object y) 
            {
                if (x == y) return (0);

                DefinitionBase definitionX = (DefinitionBase)x; 
                DefinitionBase definitionY = (DefinitionBase)y;
 
                if (definitionX.UserSize.IsAuto) 
                {
                    if (definitionY.UserSize.IsAuto)    return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1); 
                    return (1);
                }
                else
                { 
                    if (!definitionY.UserSize.IsAuto)   return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1);
                    return (-1); 
                } 
            }
        } 

        /// 
        /// StarDistributionOrderComparer.
        ///  
        private class StarDistributionOrderComparer : IComparer
        { 
            public int Compare(object x, object y) 
            {
                if (x == y) return (0); 

                DefinitionBase definitionX = (DefinitionBase)x;
                DefinitionBase definitionY = (DefinitionBase)y;
                return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1); 
            }
        } 
 
        /// 
        /// DistributionOrderComparer. 
        /// 
        private class DistributionOrderComparer: IComparer
        {
            public int Compare(object x, object y) 
            {
                if (x == y) return (0); 
 
                DefinitionBase definitionX = (DefinitionBase)x;
                DefinitionBase definitionY = (DefinitionBase)y; 
                return ((definitionX.SizeCache - definitionX.MinSizeForArrange) > (definitionY.SizeCache - definitionY.MinSizeForArrange) ? 1 : -1);
            }
        }
 
        /// 
        /// Implementation of a simple enumerator of grid's logical children 
        ///  
        private class GridChildrenCollectionEnumeratorSimple : IEnumerator
        { 
            internal GridChildrenCollectionEnumeratorSimple(Grid grid, bool includeChildren)
            {
                Debug.Assert(grid != null);
                _currentEnumerator = -1; 
                _enumerator0 = new ColumnDefinitionCollection.Enumerator(grid.ExtData != null ? grid.ExtData.ColumnDefinitions : null);
                _enumerator1 = new RowDefinitionCollection.Enumerator(grid.ExtData != null ? grid.ExtData.RowDefinitions : null); 
                // GridLineRenderer is NOT included into this enumerator. 
                _enumerator2Index = 0;
                if (includeChildren) 
                {
                    _enumerator2Collection = grid.Children;
                    _enumerator2Count = _enumerator2Collection.Count;
                } 
                else
                { 
                    _enumerator2Collection = null; 
                    _enumerator2Count = 0;
                } 
            }

            public bool MoveNext()
            { 
                while (_currentEnumerator < 3)
                { 
                    if (_currentEnumerator >= 0) 
                    {
                        switch (_currentEnumerator) 
                        {
                            case (0): if (_enumerator0.MoveNext()) { _currentChild = _enumerator0.Current; return (true); } break;
                            case (1): if (_enumerator1.MoveNext()) { _currentChild = _enumerator1.Current; return (true); } break;
                            case (2): if (_enumerator2Index < _enumerator2Count) 
                                      {
                                          _currentChild = _enumerator2Collection[_enumerator2Index]; 
                                          _enumerator2Index++; 
                                          return (true);
                                      } 
                                      break;
                        }
                    }
                    _currentEnumerator++; 
                }
                return (false); 
            } 

            public Object Current 
            {
                get
                {
                    if (_currentEnumerator == -1) 
                    {
                        #pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception 
                        throw new InvalidOperationException(SR.Get(SRID.EnumeratorNotStarted)); 
                    }
                    if (_currentEnumerator >= 3) 
                    {
                        #pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception
                        throw new InvalidOperationException(SR.Get(SRID.EnumeratorReachedEnd));
                    } 

                    //  assert below is not true anymore since UIElementCollection allowes for null children 
                    //Debug.Assert(_currentChild != null); 
                    return (_currentChild);
                } 
            }

            public void Reset()
            { 
                _currentEnumerator = -1;
                _currentChild = null; 
                _enumerator0.Reset(); 
                _enumerator1.Reset();
                _enumerator2Index = 0; 
            }

            private int _currentEnumerator;
            private Object _currentChild; 
            private ColumnDefinitionCollection.Enumerator _enumerator0;
            private RowDefinitionCollection.Enumerator _enumerator1; 
            private UIElementCollection _enumerator2Collection; 
            private int _enumerator2Index;
            private int _enumerator2Count; 
        }

        /// 
        /// Helper to render grid lines. 
        /// 
        internal class GridLinesRenderer : DrawingVisual 
        { 
            /// 
            /// Static initialization 
            /// 
            static GridLinesRenderer()
            {
                s_oddDashPen = new Pen(Brushes.Blue, c_penWidth); 
                DoubleCollection oddDashArray = new DoubleCollection();
                oddDashArray.Add(c_dashLength); 
                oddDashArray.Add(c_dashLength); 
                s_oddDashPen.DashStyle = new DashStyle(oddDashArray, 0);
                s_oddDashPen.DashCap = PenLineCap.Flat; 
                s_oddDashPen.Freeze();

                s_evenDashPen = new Pen(Brushes.Yellow, c_penWidth);
                DoubleCollection evenDashArray = new DoubleCollection(); 
                evenDashArray.Add(c_dashLength);
                evenDashArray.Add(c_dashLength); 
                s_evenDashPen.DashStyle = new DashStyle(evenDashArray, c_dashLength); 
                s_evenDashPen.DashCap = PenLineCap.Flat;
                s_evenDashPen.Freeze(); 
            }

            /// 
            /// UpdateRenderBounds. 
            /// 
            /// Size of render bounds 
            internal void UpdateRenderBounds(Size boundsSize) 
            {
                using (DrawingContext drawingContext = RenderOpen()) 
                {
                    Grid grid = VisualTreeHelper.GetParent(this) as Grid;
                    if (    grid == null
                        ||  grid.ShowGridLines == false ) 
                    {
                        return; 
                    } 

                    for (int i = 1; i < grid.DefinitionsU.Length; ++i) 
                    {
                        DrawGridLine(
                            drawingContext,
                            grid.DefinitionsU[i].FinalOffset, 0.0, 
                            grid.DefinitionsU[i].FinalOffset, boundsSize.Height);
                    } 
 
                    for (int i = 1; i < grid.DefinitionsV.Length; ++i)
                    { 
                        DrawGridLine(
                            drawingContext,
                            0.0, grid.DefinitionsV[i].FinalOffset,
                            boundsSize.Width, grid.DefinitionsV[i].FinalOffset); 
                    }
                } 
            } 

            ///  
            /// Draw single hi-contrast line.
            /// 
            private static void DrawGridLine(
                DrawingContext drawingContext, 
                double startX,
                double startY, 
                double endX, 
                double endY)
            { 
                Point start = new Point(startX, startY);
                Point end = new Point(endX, endY);
                drawingContext.DrawLine(s_oddDashPen, start, end);
                drawingContext.DrawLine(s_evenDashPen, start, end); 
            }
 
            private const double c_dashLength = 4.0;    // 
            private const double c_penWidth = 1.0;      //
            private static readonly Pen s_oddDashPen;   //  first pen to draw dash 
            private static readonly Pen s_evenDashPen;  //  second pen to draw dash
            private static readonly Point c_zeroPoint = new Point(0, 0);
        }
 
        #endregion Private Structures Classes
 
        //----------------------------------------------------- 
        //
        //  Extended debugging for grid 
        //
        //------------------------------------------------------

#if GRIDPARANOIA 
        private static double _performanceFrequency;
        private static readonly bool _performanceFrequencyInitialized = InitializePerformanceFrequency(); 
 
        //CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity, System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); 

        //CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity, System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out long lpFrequency);
 
        private static double CostInMilliseconds(long count)
        { 
            return ((double)count / _performanceFrequency); 
        }
 
        private static long Cost(long startCount, long endCount)
        {
            long l = endCount - startCount;
            if (l < 0)  { l += long.MaxValue;   } 
            return (l);
        } 
 
        private static bool InitializePerformanceFrequency()
        { 
            long l;
            QueryPerformanceFrequency(out l);
            _performanceFrequency = (double)l * 0.001;
            return (true); 
        }
 
        private struct Counter 
        {
            internal long   Start; 
            internal long   Total;
            internal int    Calls;
        }
 
        private Counter[] _counters;
        private bool _hasNewCounterInfo; 
#endif // GRIDPARANOIA 

        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        // 
        internal override int EffectiveValuesInitialSize
        { 
            get { return 9; } 
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void EnterCounterScope(Counters scopeCounter)
        {
            #if GRIDPARANOIA 
            if (ID == "CountThis")
            { 
                if (_counters == null) 
                {
                    _counters = new Counter[(int)Counters.Count]; 
                }
                ExitCounterScope(Counters.Default);
                EnterCounter(scopeCounter);
            } 
            else
            { 
                _counters = null; 
            }
            #endif // GRIDPARANOIA 
        }

        [Conditional("GRIDPARANOIA")]
        internal void ExitCounterScope(Counters scopeCounter) 
        {
            #if GRIDPARANOIA 
            if (_counters != null) 
            {
                if (scopeCounter != Counters.Default) 
                {
                    ExitCounter(scopeCounter);
                }
 
                if (_hasNewCounterInfo)
                { 
                    string NFormat = "F6"; 
                    Console.WriteLine(
                                "\ncounter name          | total t (ms)  | # of calls    | per call t (ms)" 
                            +   "\n----------------------+---------------+---------------+----------------------" );

                    for (int i = 0; i < _counters.Length; ++i)
                    { 
                        if (_counters[i].Calls > 0)
                        { 
                            Counters counter = (Counters)i; 
                            double total = CostInMilliseconds(_counters[i].Total);
                            double single = total / _counters[i].Calls; 
                            string counterName = counter.ToString();
                            string separator;

                            if (counterName.Length < 8)         { separator = "\t\t\t";  } 
                            else if (counterName.Length < 16)   { separator = "\t\t";    }
                            else                                { separator = "\t";      } 
 
                            Console.WriteLine(
                                    counter.ToString() + separator 
                                +   total.ToString(NFormat) + "\t"
                                +   _counters[i].Calls + "\t\t"
                                +   single.ToString(NFormat));
 
                            _counters[i] = new Counter();
                        } 
                    } 
                }
                _hasNewCounterInfo = false; 
            }
            #endif // GRIDPARANOIA
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void EnterCounter(Counters counter) 
        { 
            #if GRIDPARANOIA
            if (_counters != null) 
            {
                Debug.Assert((int)counter < _counters.Length);

                int i = (int)counter; 
                QueryPerformanceCounter(out _counters[i].Start);
            } 
            #endif // GRIDPARANOIA 
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void ExitCounter(Counters counter)
        {
            #if GRIDPARANOIA 
            if (_counters != null)
            { 
                Debug.Assert((int)counter < _counters.Length); 

                int i = (int)counter; 
                long l;
                QueryPerformanceCounter(out l);
                l = Cost(_counters[i].Start, l);
                _counters[i].Total += l; 
                _counters[i].Calls++;
                _hasNewCounterInfo = true; 
            } 
            #endif // GRIDPARANOIA
        } 

        internal enum Counters : int
        {
            Default = -1, 

            MeasureOverride, 
            _ValidateColsStructure, 
            _ValidateRowsStructure,
            _ValidateCells, 
            _MeasureCell,
            __MeasureChild,
            _CalculateDesiredSize,
 
            ArrangeOverride,
            _SetFinalSize, 
            _ArrangeChildHelper2, 
            _PositionCell,
 
            Count,
        }
    }
} 

 
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Grid implementation. 
//
// Specs 
//      Grid : http://avalon/layout/Specs/Grid.mht
//      Size Sharing: http://avalon/layout/Specs/Size%20Information%20Sharing.doc
//
// Misc 
//      Grid Tutorial: http://avalon/layout/Documentation%20and%20Tutorials/Grid%20Tutorial.mht
// 
// History: 
//  09/24/2003 : olego - Created (in griddy prototype branch);
//  10/27/2003 : olego - Ported from griddy prototype branch; 
//  01/20/2004 : olego - Switching to use UIElementCollection;
//
//
 

 
 

 



 

 
 

 



 
using MS.Internal;
using MS.Internal.Controls; 
using MS.Internal.PresentationFramework; 
using MS.Utility;
 
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics; 
using System.Windows.Threading;
using System.Threading; 
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Documents; 
using System.Windows.Media;
using System.Windows.Markup;

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 

namespace System.Windows.Controls 
{ 

    ///  
    /// Grid
    /// 
    public class Grid : Panel, IAddChild
    { 

        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        /// 
        /// Default constructor. 
        ///  
        public Grid()
        { 
            SetFlags((bool) ShowGridLinesProperty.GetDefaultValue(DependencyObjectType), Flags.ShowGridLinesPropertyValue);
        }

        #endregion Constructors 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        ///  
        ///  
        void IAddChild.AddChild(object value)
        { 
            if (value == null)
            {
                throw new ArgumentNullException("value");
            } 

            UIElement cell = value as UIElement; 
            if (cell != null) 
            {
                Children.Add(cell); 
                return;
            }

            throw (new ArgumentException(SR.Get(SRID.Grid_UnexpectedParameterType, value.GetType(), typeof(UIElement)), "value")); 
        }
 
        ///  
        /// 
        ///  
        void IAddChild.AddText(string text)
        {
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this);
        } 

        ///  
        ///  
        /// 
        protected internal override IEnumerator LogicalChildren 
        {
            get
            {
                // empty panel or a panel being used as the items 
                // host has *no* logical children; give empty enumerator
                bool noChildren = (base.VisualChildrenCount == 0) || IsItemsHost; 
 
                if (noChildren)
                { 
                    ExtendedData extData = ExtData;

                    if (    extData == null
                        ||  (   (extData.ColumnDefinitions == null || extData.ColumnDefinitions.Count == 0) 
                            &&  (extData.RowDefinitions    == null || extData.RowDefinitions.Count    == 0) )
                       ) 
                    { 
                        //  grid is empty
                        return EmptyEnumerator.Instance; 
                    }
                }

                return (new GridChildrenCollectionEnumeratorSimple(this, !noChildren)); 
            }
        } 
 
        /// 
        /// Helper for setting Column property on a UIElement. 
        /// 
        /// UIElement to set Column property on.
        /// Column property value.
        public static void SetColumn(UIElement element, int value) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            element.SetValue(ColumnProperty, value);
        }
 
        /// 
        /// Helper for reading Column property from a UIElement. 
        ///  
        /// UIElement to read Column property from.
        /// Column property value. 
        [AttachedPropertyBrowsableForChildren()]
        public static int GetColumn(UIElement element)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            return ((int)element.GetValue(ColumnProperty)); 
        }

        /// 
        /// Helper for setting Row property on a UIElement. 
        /// 
        /// UIElement to set Row property on. 
        /// Row property value. 
        public static void SetRow(UIElement element, int value)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            element.SetValue(RowProperty, value); 
        } 

        ///  
        /// Helper for reading Row property from a UIElement.
        /// 
        /// UIElement to read Row property from.
        /// Row property value. 
        [AttachedPropertyBrowsableForChildren()]
        public static int GetRow(UIElement element) 
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            }

            return ((int)element.GetValue(RowProperty)); 
        }
 
        ///  
        /// Helper for setting ColumnSpan property on a UIElement.
        ///  
        /// UIElement to set ColumnSpan property on.
        /// ColumnSpan property value.
        public static void SetColumnSpan(UIElement element, int value)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            element.SetValue(ColumnSpanProperty, value);
        }

        ///  
        /// Helper for reading ColumnSpan property from a UIElement.
        ///  
        /// UIElement to read ColumnSpan property from. 
        /// ColumnSpan property value.
        [AttachedPropertyBrowsableForChildren()] 
        public static int GetColumnSpan(UIElement element)
        {
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            } 
 
            return ((int)element.GetValue(ColumnSpanProperty));
        } 

        /// 
        /// Helper for setting RowSpan property on a UIElement.
        ///  
        /// UIElement to set RowSpan property on.
        /// RowSpan property value. 
        public static void SetRowSpan(UIElement element, int value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(RowSpanProperty, value);
        } 
 
        /// 
        /// Helper for reading RowSpan property from a UIElement. 
        /// 
        /// UIElement to read RowSpan property from.
        /// RowSpan property value.
        [AttachedPropertyBrowsableForChildren()] 
        public static int GetRowSpan(UIElement element)
        { 
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            }

            return ((int)element.GetValue(RowSpanProperty));
        } 

        ///  
        /// Helper for setting IsSharedSizeScope property on a UIElement. 
        /// 
        /// UIElement to set IsSharedSizeScope property on. 
        /// IsSharedSizeScope property value.
        public static void SetIsSharedSizeScope(UIElement element, bool value)
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element"); 
            } 

            element.SetValue(IsSharedSizeScopeProperty, value); 
        }

        /// 
        /// Helper for reading IsSharedSizeScope property from a UIElement. 
        /// 
        /// UIElement to read IsSharedSizeScope property from. 
        /// IsSharedSizeScope property value. 
        public static bool GetIsSharedSizeScope(UIElement element)
        { 
            if (element == null)
            {
                throw new ArgumentNullException("element");
            } 

            return ((bool)element.GetValue(IsSharedSizeScopeProperty)); 
        } 

        #endregion Public Methods 

        //------------------------------------------------------
        //
        //  Public Properties 
        //
        //------------------------------------------------------ 
 
        #region Public Properties
 
        /// 
        /// ShowGridLines property.
        /// 
        public bool ShowGridLines 
        {
            get { return (CheckFlagsAnd(Flags.ShowGridLinesPropertyValue)); } 
            set { SetValue(ShowGridLinesProperty, value); } 
        }
 
        /// 
        /// Returns a ColumnDefinitionCollection of column definitions.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public ColumnDefinitionCollection ColumnDefinitions
        { 
            get 
            {
                if (_data == null) { _data = new ExtendedData(); } 
                if (_data.ColumnDefinitions == null) { _data.ColumnDefinitions = new ColumnDefinitionCollection(this); }

                return (_data.ColumnDefinitions);
            } 
        }
 
        ///  
        /// Returns a RowDefinitionCollection of row definitions.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public RowDefinitionCollection RowDefinitions
        {
            get 
            {
                if (_data == null) { _data = new ExtendedData(); } 
                if (_data.RowDefinitions == null) { _data.RowDefinitions = new RowDefinitionCollection(this); } 

                return (_data.RowDefinitions); 
            }
        }

        #endregion Public Properties 

        //----------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------

        #region Protected Methods
 
        /// 
        ///   Derived class must implement to support Visual children. The method must return 
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        ///
        ///    By default a Visual does not have any children. 
        ///
        ///  Remark:
        ///       During this virtual call it is not valid to modify the Visual tree.
        ///  
        protected override Visual GetVisualChild(int index)
        { 
            // because "base.Count + 1" for GridLinesRenderer 
            // argument checking done at the base class
            if(index == base.VisualChildrenCount) 
            {
                if (_gridLinesRenderer == null)
                {
                    throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
                }
                return _gridLinesRenderer; 
            } 
            else return base.GetVisualChild(index);
 
        }

        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate 
        ///  the Visual children. Derived classes need to return the number of children
        ///  from this method. 
        /// 
        ///    By default a Visual does not have any children.
        /// 
        ///  Remark: During this virtual method the Visual tree must not be modified.
        /// 
        protected override int VisualChildrenCount
        { 
            //since GridLinesRenderer has not been added as a child, so we do not subtract
            get { return base.VisualChildrenCount + (_gridLinesRenderer != null ? 1 : 0); } 
        } 

 
        /// 
        /// Content measurement.
        /// 
        /// Constraint 
        /// Desired size
        protected override Size MeasureOverride(Size constraint) 
        { 
            Size gridDesiredSize;
            ExtendedData extData = ExtData; 

            try
            {
                EnterCounterScope(Counters.MeasureOverride); 

                ListenToNotifications = true; 
                MeasureOverrideInProgress = true; 

                if (extData == null) 
                {
                    gridDesiredSize = new Size();
                    UIElementCollection children = InternalChildren;
 
                    for (int i = 0, count = children.Count; i < count; ++i)
                    { 
                        UIElement child = children[i]; 
                        if (child != null)
                        { 
                            Helper.SetMeasureDataOnChild(this, child, constraint);  // pass along MeasureData so it continues down the tree.
                            child.Measure(constraint);
                            gridDesiredSize.Width = Math.Max(gridDesiredSize.Width, child.DesiredSize.Width);
                            gridDesiredSize.Height = Math.Max(gridDesiredSize.Height, child.DesiredSize.Height); 
                        }
                    } 
                } 
                else
                { 
                    {
                        bool sizeToContentU = double.IsPositiveInfinity(constraint.Width);
                        bool sizeToContentV = double.IsPositiveInfinity(constraint.Height);
 
                        ValidateDefinitionsUStructure();
                        ValidateDefinitionsLayout(DefinitionsU, sizeToContentU); 
 
                        ValidateDefinitionsVStructure();
                        ValidateDefinitionsLayout(DefinitionsV, sizeToContentV); 

                        CellsStructureDirty |= (SizeToContentU != sizeToContentU) || (SizeToContentV != sizeToContentV);

                        SizeToContentU = sizeToContentU; 
                        SizeToContentV = sizeToContentV;
                    } 
 
                    ValidateCells();
 
                    Debug.Assert(DefinitionsU.Length > 0 && DefinitionsV.Length > 0);

                    //  Grid classifies cells into four groups depending on
                    //  the column / row type a cell belongs to (number corresponds to 
                    //  group number):
                    // 
                    //                   Px      Auto     Star 
                    //               +--------+--------+--------+
                    //               |        |        |        | 
                    //            Px |    1   |    1   |    3   |
                    //               |        |        |        |
                    //               +--------+--------+--------+
                    //               |        |        |        | 
                    //          Auto |    1   |    1   |    3   |
                    //               |        |        |        | 
                    //               +--------+--------+--------+ 
                    //               |        |        |        |
                    //          Star |    4   |    2   |    4   | 
                    //               |        |        |        |
                    //               +--------+--------+--------+
                    //
                    //  The group number indicates the order in which cells are measured. 
                    //  Certain order is necessary to be able to dynamically resolve star
                    //  columns / rows sizes which are used as input for measuring of 
                    //  the cells belonging to them. 
                    //
                    //  However, there are cases when topology of a grid causes cyclical 
                    //  size dependences. For example:
                    //
                    //
                    //                         column width="Auto"      column width="*" 
                    //                      +----------------------+----------------------+
                    //                      |                      |                      | 
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //  row height="Auto"   |                      |      cell 1 2        |
                    //                      |                      |                      |
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      +----------------------+----------------------+ 
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //  row height="*"      |       cell 2 1       |                      |
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      |                      |                      |
                    //                      |                      |                      | 
                    //                      +----------------------+----------------------+ 
                    //
                    //  In order to accurately calculate constraint width for "cell 1 2" 
                    //  (which is the remaining of grid's available width and calculated
                    //  value of Auto column), "cell 2 1" needs to be calculated first,
                    //  as it contributes to the Auto column's calculated value.
                    //  At the same time in order to accurately calculate constraint 
                    //  height for "cell 2 1", "cell 1 2" needs to be calcualted first,
                    //  as it contributes to Auto row height, which is used in the 
                    //  computation of Star row resolved height. 
                    //
                    //  to "break" this cyclical dependency we are making (arbitrary) 
                    //  decision to treat cells like "cell 2 1" as if they appear in Auto
                    //  rows. And then recalculate them one more time when star row
                    //  heights are resolved.
                    // 
                    //  (Or more strictly) the code below implement the following logic:
                    // 
                    //                       +---------+ 
                    //                       |  enter  |
                    //                       +---------+ 
                    //                            |
                    //                            V
                    //                    +----------------+
                    //                    | Measure Group1 | 
                    //                    +----------------+
                    //                            | 
                    //                            V 
                    //                          / - \
                    //                        /       \ 
                    //                  Y   /    Can    \    N
                    //            +--------|   Resolve   |-----------+
                    //            |         \  StarsV?  /            |
                    //            |           \       /              | 
                    //            |             \ - /                |
                    //            V                                  V 
                    //    +----------------+                       / - \ 
                    //    | Resolve StarsV |                     /       \
                    //    +----------------+               Y   /    Can    \    N 
                    //            |                      +----|   Resolve   |------+
                    //            V                      |     \  StarsU?  /       |
                    //    +----------------+             |       \       /         |
                    //    | Measure Group2 |             |         \ - /           | 
                    //    +----------------+             |                         V
                    //            |                      |                 +-----------------+ 
                    //            V                      |                 | Measure Group2' | 
                    //    +----------------+             |                 +-----------------+
                    //    | Resolve StarsU |             |                         | 
                    //    +----------------+             V                         V
                    //            |              +----------------+        +----------------+
                    //            V              | Resolve StarsU |        | Resolve StarsU |
                    //    +----------------+     +----------------+        +----------------+ 
                    //    | Measure Group3 |             |                         |
                    //    +----------------+             V                         V 
                    //            |              +----------------+        +----------------+ 
                    //            |              | Measure Group3 |        | Measure Group3 |
                    //            |              +----------------+        +----------------+ 
                    //            |                      |                         |
                    //            |                      V                         V
                    //            |              +----------------+        +----------------+
                    //            |              | Resolve StarsV |        | Resolve StarsV | 
                    //            |              +----------------+        +----------------+
                    //            |                      |                         | 
                    //            |                      |                         V 
                    //            |                      |                +------------------+
                    //            |                      |                | Measure Group2'' | 
                    //            |                      |                +------------------+
                    //            |                      |                         |
                    //            +----------------------+-------------------------+
                    //                                   | 
                    //                                   V
                    //                           +----------------+ 
                    //                           | Measure Group4 | 
                    //                           +----------------+
                    //                                   | 
                    //                                   V
                    //                               +--------+
                    //                               |  exit  |
                    //                               +--------+ 
                    //
                    //  where: 
                    //  *   all [Measure GroupN] - regular children measure process - 
                    //      each cell is measured given contraint size as an input
                    //      and each cell's desired size is accumulated on the 
                    //      corresponding column / row;
                    //  *   [Measure Group2'] - is when each cell is measured with
                    //      infinit height as a constraint and a cell's desired
                    //      height is ignored; 
                    //  *   [Measure Groups''] - is when each cell is measured (second
                    //      time during single Grid.MeasureOverride) regularly but its 
                    //      returned width is ignored; 
                    //
                    //  This algorithm is believed to be as close to ideal as possible. 
                    //  It has the following drawbacks:
                    //  *   cells belonging to Group2 can be called to measure twice;
                    //  *   iff during second measure a cell belonging to Group2 returns
                    //      desired width greater than desired width returned the first 
                    //      time, such a cell is going to be clipped, even though it
                    //      appears in Auto column. 
                    // 

                    MeasureCellsGroup(extData.CellGroup1, constraint, false, false); 

                    {
                        //  after Group1 is measured,  only Group3 may have cells belonging to Auto rows.
                        bool canResolveStarsV = !HasGroup3CellsInAutoRows; 

                        if (canResolveStarsV) 
                        { 
                            if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); }
                            MeasureCellsGroup(extData.CellGroup2, constraint, false, false); 
                            if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); }
                            MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                        }
                        else 
                        {
                            //  if at least one cell exists in Group2, it must be measured before 
                            //  StarsU can be resolved. 
                            bool canResolveStarsU = extData.CellGroup2 > PrivateCells.Length;
                            if (canResolveStarsU) 
                            {
                                if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); }
                                MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                                if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); } 
                            }
                            else 
                            { 
                                MeasureCellsGroup(extData.CellGroup2, constraint, false, true);
                                if (HasStarCellsU) { ResolveStar(DefinitionsU, constraint.Width); } 
                                MeasureCellsGroup(extData.CellGroup3, constraint, false, false);
                                if (HasStarCellsV) { ResolveStar(DefinitionsV, constraint.Height); }
                                MeasureCellsGroup(extData.CellGroup2, constraint, true, false);
                            } 
                        }
                    } 
 
                    MeasureCellsGroup(extData.CellGroup4, constraint, false, false);
 
                    EnterCounter(Counters._CalculateDesiredSize);
                    gridDesiredSize = new Size(
                            CalculateDesiredSize(DefinitionsU),
                            CalculateDesiredSize(DefinitionsV)); 
                    ExitCounter(Counters._CalculateDesiredSize);
                } 
            } 
            finally
            { 
                MeasureOverrideInProgress = false;
                ExitCounterScope(Counters.MeasureOverride);
            }
 
            return (gridDesiredSize);
        } 
 
        /// 
        /// Content arrangement. 
        /// 
        /// Arrange size
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            try
            { 
                EnterCounterScope(Counters.ArrangeOverride); 

                ArrangeOverrideInProgress = true; 

                if (_data == null)
                {
                    UIElementCollection children = InternalChildren; 

                    for (int i = 0, count = children.Count; i < count; ++i) 
                    { 
                        UIElement child = children[i];
                        if (child != null) 
                        {
                            child.Arrange(new Rect(arrangeSize));
                        }
                    } 
                }
                else 
                { 
                    Debug.Assert(DefinitionsU.Length > 0 && DefinitionsV.Length > 0);
 
                    EnterCounter(Counters._SetFinalSize);

                    SetFinalSize(DefinitionsU, arrangeSize.Width);
                    SetFinalSize(DefinitionsV, arrangeSize.Height); 

                    ExitCounter(Counters._SetFinalSize); 
 
                    UIElementCollection children = InternalChildren;
 
                    for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell)
                    {
                        UIElement cell = children[currentCell];
                        if (cell == null) 
                        {
                            continue; 
                        } 

                        int columnIndex = PrivateCells[currentCell].ColumnIndex; 
                        int rowIndex = PrivateCells[currentCell].RowIndex;
                        int columnSpan = PrivateCells[currentCell].ColumnSpan;
                        int rowSpan = PrivateCells[currentCell].RowSpan;
 
                        Rect cellRect = new Rect(
                            columnIndex == 0 ? 0.0 : DefinitionsU[columnIndex].FinalOffset, 
                            rowIndex == 0 ? 0.0 : DefinitionsV[rowIndex].FinalOffset, 
                            GetFinalSizeForRange(DefinitionsU, columnIndex, columnSpan),
                            GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan)   ); 

                        EnterCounter(Counters._ArrangeChildHelper2);
                        cell.Arrange(cellRect);
                        ExitCounter(Counters._ArrangeChildHelper2); 
                    }
 
                    //  update render bound on grid lines renderer visual 
                    GridLinesRenderer gridLinesRenderer = EnsureGridLinesRenderer();
                    if (gridLinesRenderer != null) 
                    {
                        gridLinesRenderer.UpdateRenderBounds(arrangeSize);
                    }
                } 
            }
            finally 
            { 
                SetValid();
                ArrangeOverrideInProgress = false; 
                ExitCounterScope(Counters.ArrangeOverride);
            }
            return (arrangeSize);
        } 

        ///  
        ///  
        /// 
        protected internal override void OnVisualChildrenChanged( 
            DependencyObject visualAdded,
            DependencyObject visualRemoved)
        {
            CellsStructureDirty = true; 

            base.OnVisualChildrenChanged(visualAdded, visualRemoved); 
        } 

        #endregion Protected Methods 

        //-----------------------------------------------------
        //
        //  Internal Methods 
        //
        //----------------------------------------------------- 
 
        #region Internal Methods
 
        /// 
        ///     Invalidates grid caches and makes the grid dirty for measure.
        /// 
        internal void Invalidate() 
        {
            CellsStructureDirty = true; 
            InvalidateMeasure(); 
        }
 
        /// 
        ///     Returns final width for a column.
        /// 
        ///  
        ///     Used from public ColumnDefinition ActualWidth. Calculates final width using offset data.
        ///  
        internal double GetFinalColumnDefinitionWidth(int columnIndex) 
        {
            double value = 0.0; 

            Invariant.Assert(_data != null);

            //  actual value calculations require structure to be up-to-date 
            if (!ColumnDefinitionCollectionDirty)
            { 
                DefinitionBase[] definitions = DefinitionsU; 
                value = definitions[(columnIndex + 1) % definitions.Length].FinalOffset;
                if (columnIndex != 0) { value -= definitions[columnIndex].FinalOffset; } 
            }
            return (value);
        }
 
        /// 
        ///     Returns final height for a row. 
        ///  
        /// 
        ///     Used from public RowDefinition ActualHeight. Calculates final height using offset data. 
        /// 
        internal double GetFinalRowDefinitionHeight(int rowIndex)
        {
            double value = 0.0; 

            Invariant.Assert(_data != null); 
 
            //  actual value calculations require structure to be up-to-date
            if (!RowDefinitionCollectionDirty) 
            {
                DefinitionBase[] definitions = DefinitionsV;
                value = definitions[(rowIndex + 1) % definitions.Length].FinalOffset;
                if (rowIndex != 0) { value -= definitions[rowIndex].FinalOffset; } 
            }
            return (value); 
        } 

        #endregion Internal Methods 

        //-----------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        /// 
        /// Convenience accessor to MeasureOverrideInProgress bit flag.
        /// 
        internal bool MeasureOverrideInProgress 
        {
            get { return (CheckFlagsAnd(Flags.MeasureOverrideInProgress)); } 
            set { SetFlags(value, Flags.MeasureOverrideInProgress); } 
        }
 
        /// 
        /// Convenience accessor to ArrangeOverrideInProgress bit flag.
        /// 
        internal bool ArrangeOverrideInProgress 
        {
            get { return (CheckFlagsAnd(Flags.ArrangeOverrideInProgress)); } 
            set { SetFlags(value, Flags.ArrangeOverrideInProgress); } 
        }
 
        /// 
        /// Convenience accessor to ValidDefinitionsUStructure bit flag.
        /// 
        internal bool ColumnDefinitionCollectionDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidDefinitionsUStructure)); } 
            set { SetFlags(!value, Flags.ValidDefinitionsUStructure); } 
        }
 
        /// 
        /// Convenience accessor to ValidDefinitionsVStructure bit flag.
        /// 
        internal bool RowDefinitionCollectionDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidDefinitionsVStructure)); } 
            set { SetFlags(!value, Flags.ValidDefinitionsVStructure); } 
        }
 
        #endregion Internal Properties

        //-----------------------------------------------------
        // 
        //  Private Methods
        // 
        //------------------------------------------------------ 

        #region Private Methods 

        /// 
        /// Lays out cells according to rows and columns, and creates lookup grids.
        ///  
        private void ValidateCells()
        { 
            EnterCounter(Counters._ValidateCells); 

            if (CellsStructureDirty) 
            {
                ValidateCellsCore();
                CellsStructureDirty = false;
            } 

            ExitCounter(Counters._ValidateCells); 
        } 

        ///  
        /// ValidateCellsCore
        /// 
        private void ValidateCellsCore()
        { 
            UIElementCollection children = InternalChildren;
            ExtendedData extData = ExtData; 
 
            extData.CellCachesCollection = new CellCache[children.Count];
            extData.CellGroup1 = int.MaxValue; 
            extData.CellGroup2 = int.MaxValue;
            extData.CellGroup3 = int.MaxValue;
            extData.CellGroup4 = int.MaxValue;
 
            bool hasStarCellsU = false;
            bool hasStarCellsV = false; 
            bool hasGroup3CellsInAutoRows = false; 

            for (int i = PrivateCells.Length - 1; i >= 0; --i) 
            {
                UIElement child = children[i];
                if (child == null)
                { 
                    continue;
                } 
 
                CellCache cell = new CellCache();
 
                //
                //  read and cache child positioning properties
                //
 
                //  read indices from the corresponding properties
                //      clamp to value < number_of_columns 
                //      column >= 0 is guaranteed by property value validation callback 
                cell.ColumnIndex = Math.Min(GetColumn(child), DefinitionsU.Length - 1);
                //      clamp to value < number_of_rows 
                //      row >= 0 is guaranteed by property value validation callback
                cell.RowIndex = Math.Min(GetRow(child), DefinitionsV.Length - 1);

                //  read span properties 
                //      clamp to not exceed beyond right side of the grid
                //      column_span > 0 is guaranteed by property value validation callback 
                cell.ColumnSpan = Math.Min(GetColumnSpan(child), DefinitionsU.Length - cell.ColumnIndex); 

                //      clamp to not exceed beyond bottom side of the grid 
                //      row_span > 0 is guaranteed by property value validation callback
                cell.RowSpan = Math.Min(GetRowSpan(child), DefinitionsV.Length - cell.RowIndex);

                Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Length); 
                Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Length);
 
                // 
                //  calculate and cache length types for the child
                // 

                cell.SizeTypeU = GetLengthTypeForRange(DefinitionsU, cell.ColumnIndex, cell.ColumnSpan);
                cell.SizeTypeV = GetLengthTypeForRange(DefinitionsV, cell.RowIndex, cell.RowSpan);
 
                hasStarCellsU |= cell.IsStarU;
                hasStarCellsV |= cell.IsStarV; 
 
                //
                //  distribute cells into four groups. 
                //

                if (!cell.IsStarV)
                { 
                    if (!cell.IsStarU)
                    { 
                        cell.Next = extData.CellGroup1; 
                        extData.CellGroup1 = i;
                    } 
                    else
                    {
                        cell.Next = extData.CellGroup3;
                        extData.CellGroup3 = i; 

                        //  remember if this cell belongs to auto row 
                        hasGroup3CellsInAutoRows |= cell.IsAutoV; 
                    }
                } 
                else
                {
                    if (    cell.IsAutoU
                            //  note below: if spans through Star column it is NOT Auto 
                        &&  !cell.IsStarU )
                    { 
                        cell.Next = extData.CellGroup2; 
                        extData.CellGroup2 = i;
                    } 
                    else
                    {
                        cell.Next = extData.CellGroup4;
                        extData.CellGroup4 = i; 
                    }
                } 
 
                PrivateCells[i] = cell;
            } 

            HasStarCellsU = hasStarCellsU;
            HasStarCellsV = hasStarCellsV;
            HasGroup3CellsInAutoRows = hasGroup3CellsInAutoRows; 
        }
 
        ///  
        /// Initializes DefinitionsU memeber either to user supplied ColumnDefinitions collection
        /// or to a default single element collection. DefinitionsU gets trimmed to size. 
        /// 
        /// 
        /// This is one of two methods, where ColumnDefinitions and DefinitionsU are directly accessed.
        /// All the rest measure / arrange / render code must use DefinitionsU. 
        /// 
        private void ValidateDefinitionsUStructure() 
        { 
            EnterCounter(Counters._ValidateColsStructure);
 
            if (ColumnDefinitionCollectionDirty)
            {
                ExtendedData extData = ExtData;
 
                if (extData.ColumnDefinitions == null)
                { 
                    if (extData.DefinitionsU == null) 
                    {
                        extData.DefinitionsU = new DefinitionBase[] { new ColumnDefinition() }; 
                    }
                }
                else
                { 
                    extData.ColumnDefinitions.InternalTrimToSize();
 
                    if (extData.ColumnDefinitions.InternalCount == 0) 
                    {
                        //  if column definitions collection is empty 
                        //  mockup array with one column
                        extData.DefinitionsU = new DefinitionBase[] { new ColumnDefinition() };
                    }
                    else 
                    {
                        extData.DefinitionsU = extData.ColumnDefinitions.InternalItems; 
                    } 
                }
 
                ColumnDefinitionCollectionDirty = false;
            }

            Debug.Assert(ExtData.DefinitionsU != null && ExtData.DefinitionsU.Length > 0); 

            ExitCounter(Counters._ValidateColsStructure); 
        } 

        ///  
        /// Initializes DefinitionsV memeber either to user supplied RowDefinitions collection
        /// or to a default single element collection. DefinitionsV gets trimmed to size.
        /// 
        ///  
        /// This is one of two methods, where RowDefinitions and DefinitionsV are directly accessed.
        /// All the rest measure / arrange / render code must use DefinitionsV. 
        ///  
        private void ValidateDefinitionsVStructure()
        { 
            EnterCounter(Counters._ValidateRowsStructure);

            if (RowDefinitionCollectionDirty)
            { 
                ExtendedData extData = ExtData;
 
                if (extData.RowDefinitions == null) 
                {
                    if (extData.DefinitionsV == null) 
                    {
                        extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() };
                    }
                } 
                else
                { 
                    extData.RowDefinitions.InternalTrimToSize(); 

                    if (extData.RowDefinitions.InternalCount == 0) 
                    {
                        //  if row definitions collection is empty
                        //  mockup array with one row
                        extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() }; 
                    }
                    else 
                    { 
                        extData.DefinitionsV = extData.RowDefinitions.InternalItems;
                    } 
                }

                RowDefinitionCollectionDirty = false;
            } 

            Debug.Assert(ExtData.DefinitionsV != null && ExtData.DefinitionsV.Length > 0); 
 
            ExitCounter(Counters._ValidateRowsStructure);
        } 

        /// 
        /// Validates layout time size type information on given array of definitions.
        /// Sets MinSize and MeasureSizes. 
        /// 
        /// Array of definitions to update. 
        /// if "true" then star definitions are treated as Auto. 
        private void ValidateDefinitionsLayout(
            DefinitionBase[] definitions, 
            bool treatStarAsAuto)
        {
            for (int i = 0; i < definitions.Length; ++i)
            { 
                definitions[i].OnBeforeLayout(this);
 
                double userMinSize = definitions[i].UserMinSize; 
                double userMaxSize = definitions[i].UserMaxSize;
                double userSize = 0; 

                switch (definitions[i].UserSize.GridUnitType)
                {
                    case (GridUnitType.Pixel): 
                        definitions[i].SizeType = LayoutTimeSizeType.Pixel;
                        userSize = definitions[i].UserSize.Value; 
                        // this was brought with NewLayout and defeats squishy behavior 
                        userMinSize = Math.Max(userMinSize, Math.Min(userSize, userMaxSize));
                        break; 
                    case (GridUnitType.Auto):
                        definitions[i].SizeType = LayoutTimeSizeType.Auto;
                        userSize = double.PositiveInfinity;
                        break; 
                    case (GridUnitType.Star):
                        if (treatStarAsAuto) 
                        { 
                            definitions[i].SizeType = LayoutTimeSizeType.Auto;
                            userSize = double.PositiveInfinity; 
                        }
                        else
                        {
                            definitions[i].SizeType = LayoutTimeSizeType.Star; 
                            userSize = double.PositiveInfinity;
                        } 
                        break; 
                    default:
                        Debug.Assert(false); 
                        break;
                }

                definitions[i].UpdateMinSize(userMinSize); 
                definitions[i].MeasureSize = Math.Max(userMinSize, Math.Min(userSize, userMaxSize));
            } 
        } 

        ///  
        /// Measures one group of cells.
        /// 
        /// Head index of the cells chain.
        /// Reference size for spanned cells 
        /// calculations.
        /// When "true" cells' desired 
        /// width is not registered in columns. 
        /// Passed through to MeasureCell.
        /// When "true" cells' desired height is not registered in rows. 
        private void MeasureCellsGroup(
            int cellsHead,
            Size referenceSize,
            bool ignoreDesiredSizeU, 
            bool forceInfinityV)
        { 
            if (cellsHead >= PrivateCells.Length) 
            {
                return; 
            }

            UIElementCollection children = InternalChildren;
            Hashtable spanStore = null; 
            bool ignoreDesiredSizeV = forceInfinityV;
 
            int i = cellsHead; 
            do
            { 
                MeasureCell(i, forceInfinityV);

                if (!ignoreDesiredSizeU)
                { 
                    if (PrivateCells[i].ColumnSpan == 1)
                    { 
                        DefinitionsU[PrivateCells[i].ColumnIndex].UpdateMinSize(children[i].DesiredSize.Width); 
                    }
                    else 
                    {
                        RegisterSpan(
                            ref spanStore,
                            PrivateCells[i].ColumnIndex, 
                            PrivateCells[i].ColumnSpan,
                            true, 
                            children[i].DesiredSize.Width); 
                    }
                } 

                if (!ignoreDesiredSizeV)
                {
                    if (PrivateCells[i].RowSpan == 1) 
                    {
                        DefinitionsV[PrivateCells[i].RowIndex].UpdateMinSize(children[i].DesiredSize.Height); 
                    } 
                    else
                    { 
                        RegisterSpan(
                            ref spanStore,
                            PrivateCells[i].RowIndex,
                            PrivateCells[i].RowSpan, 
                            false,
                            children[i].DesiredSize.Height); 
                    } 
                }
 
                i = PrivateCells[i].Next;
            } while (i < PrivateCells.Length);

            if (spanStore != null) 
            {
                foreach (DictionaryEntry e in spanStore) 
                { 
                    SpanKey key = (SpanKey)e.Key;
                    double requestedSize = (double)e.Value; 

                    EnsureMinSizeInDefinitionRange(
                        key.U ? DefinitionsU : DefinitionsV,
                        key.Start, 
                        key.Count,
                        requestedSize, 
                        key.U ? referenceSize.Width : referenceSize.Height); 
                }
            } 
        }

        /// 
        /// Helper method to register a span information for delayed processing. 
        /// 
        /// Reference to a hashtable object used as storage. 
        /// Span starting index. 
        /// Span count.
        /// true if this is a column span. false if this is a row span. 
        /// Value to store. If an entry already exists the biggest value is stored.
        private static void RegisterSpan(
            ref Hashtable store,
            int start, 
            int count,
            bool u, 
            double value) 
        {
            if (store == null) 
            {
                store = new Hashtable();
            }
 
            SpanKey key = new SpanKey(start, count, u);
            object o = store[key]; 
 
            if (    o == null
                ||  value > (double)o   ) 
            {
                store[key] = value;
            }
        } 

        ///  
        /// Takes care of measuring a single cell. 
        /// 
        /// Index of the cell to measure. 
        /// If "true" then cell is always
        /// calculated to infinite height.
        private void MeasureCell(
            int cell, 
            bool forceInfinityV)
        { 
            EnterCounter(Counters._MeasureCell); 

            double cellMeasureWidth; 
            double cellMeasureHeight;

            if (    PrivateCells[cell].IsAutoU
                &&  !PrivateCells[cell].IsStarU   ) 
            {
                //  if cell belongs to at least one Auto column and not a single Star column 
                //  then it should be calculated "to content", thus it is possible to "shortcut" 
                //  calculations and simply assign PositiveInfinity here.
                cellMeasureWidth = double.PositiveInfinity; 
            }
            else
            {
                //  otherwise... 
                cellMeasureWidth = GetMeasureSizeForRange(
                                        DefinitionsU, 
                                        PrivateCells[cell].ColumnIndex, 
                                        PrivateCells[cell].ColumnSpan);
            } 

            if (forceInfinityV)
            {
                cellMeasureHeight = double.PositiveInfinity; 
            }
            else if (   PrivateCells[cell].IsAutoV 
                    &&  !PrivateCells[cell].IsStarV   ) 
            {
                //  if cell belongs to at least one Auto row and not a single Star row 
                //  then it should be calculated "to content", thus it is possible to "shortcut"
                //  calculations and simply assign PositiveInfinity here.
                cellMeasureHeight = double.PositiveInfinity;
            } 
            else
            { 
                cellMeasureHeight = GetMeasureSizeForRange( 
                                        DefinitionsV,
                                        PrivateCells[cell].RowIndex, 
                                        PrivateCells[cell].RowSpan);
            }

            EnterCounter(Counters.__MeasureChild); 
            UIElement child = InternalChildren[cell];
            if (child != null) 
            { 
                Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
                Helper.SetMeasureDataOnChild(this, child, childConstraint);  // pass along MeasureData so it continues down the tree. 
                child.Measure(childConstraint);
            }
            ExitCounter(Counters.__MeasureChild);
 
            ExitCounter(Counters._MeasureCell);
        } 
 

        ///  
        /// Calculates one dimensional measure size for given definitions' range.
        /// 
        /// Source array of definitions to read values from.
        /// Starting index of the range. 
        /// Number of definitions included in the range.
        /// Calculated measure size. 
        ///  
        /// For "Auto" definitions MinWidth is used in place of PreferredSize.
        ///  
        private double GetMeasureSizeForRange(
            DefinitionBase[] definitions,
            int start,
            int count) 
        {
            Debug.Assert(0 < count && 0 <= start && (start + count) <= definitions.Length); 
 
            double measureSize = 0;
            int i = start + count - 1; 

            do
            {
                measureSize += (definitions[i].SizeType == LayoutTimeSizeType.Auto) 
                    ? definitions[i].MinSize
                    : definitions[i].MeasureSize; 
            } while (--i >= start); 

            return (measureSize); 
        }

        /// 
        /// Accumulates length type information for given definition's range. 
        /// 
        /// Source array of definitions to read values from. 
        /// Starting index of the range. 
        /// Number of definitions included in the range.
        /// Length type for given range. 
        private LayoutTimeSizeType GetLengthTypeForRange(
            DefinitionBase[] definitions,
            int start,
            int count) 
        {
            Debug.Assert(0 < count && 0 <= start && (start + count) <= definitions.Length); 
 
            LayoutTimeSizeType lengthType = LayoutTimeSizeType.None;
            int i = start + count - 1; 

            do
            {
                lengthType |= definitions[i].SizeType; 
            } while (--i >= start);
 
            return (lengthType); 
        }
 
        /// 
        /// Distributes min size back to definition array's range.
        /// 
        /// Start of the range. 
        /// Number of items in the range.
        /// Minimum size that should "fit" into the definitions range. 
        /// Definition array receiving distribution. 
        /// Size used to resolve percentages.
        private void EnsureMinSizeInDefinitionRange( 
            DefinitionBase[] definitions,
            int start,
            int count,
            double requestedSize, 
            double percentReferenceSize)
        { 
            Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Length); 

            //  avoid processing when asked to distribute "0" 
            if (!_IsZero(requestedSize))
            {
                DefinitionBase[] tempDefinitions = TempDefinitions; //  temp array used to remember definitions for sorting
                int end = start + count; 
                int autoDefinitionsCount = 0;
                double rangeMinSize = 0; 
                double rangePreferredSize = 0; 
                double rangeMaxSize = 0;
                double maxMaxSize = 0;                              //  maximum of maximum sizes 

                //  first accumulate the necessary information:
                //  a) sum up the sizes in the range;
                //  b) count the number of auto definitions in the range; 
                //  c) initialize temp array
                //  d) cache the maximum size into SizeCache 
                //  e) accumulate max of max sizes 
                for (int i = start; i < end; ++i)
                { 
                    double minSize = definitions[i].MinSize;
                    double preferredSize = definitions[i].PreferredSize;
                    double maxSize = Math.Max(definitions[i].UserMaxSize, minSize);
 
                    rangeMinSize += minSize;
                    rangePreferredSize += preferredSize; 
                    rangeMaxSize += maxSize; 

                    definitions[i].SizeCache = maxSize; 

                    //  sanity check: no matter what, but min size must always be the smaller;
                    //  max size must be the biggest; and preferred should be in between
                    Debug.Assert(   minSize <= preferredSize 
                                &&  preferredSize <= maxSize
                                &&  rangeMinSize <= rangePreferredSize 
                                &&  rangePreferredSize <= rangeMaxSize  ); 

                    if (maxMaxSize < maxSize)   maxMaxSize = maxSize; 
                    if (definitions[i].UserSize.IsAuto) autoDefinitionsCount++;
                    tempDefinitions[i - start] = definitions[i];
                }
 
                //  avoid processing if the range already big enough
                if (requestedSize > rangeMinSize) 
                { 
                    if (requestedSize <= rangePreferredSize)
                    { 
                        //
                        //  requestedSize fits into preferred size of the range.
                        //  distribute according to the following logic:
                        //  * do not distribute into auto definitions - they should continue to stay "tight"; 
                        //  * for all non-auto definitions distribute to equi-size min sizes, without exceeding preferred size.
                        // 
                        //  in order to achieve that, definitions are sorted in a way that all auto definitions 
                        //  are first, then definitions follow ascending order with PreferredSize as the key of sorting.
                        // 
                        double sizeToDistribute;
                        int i;

                        Array.Sort(tempDefinitions, 0, count, s_spanPreferredDistributionOrderComparer); 
                        for (i = 0, sizeToDistribute = requestedSize; i < autoDefinitionsCount; ++i)
                        { 
                            //  sanity check: only auto definitions allowed in this loop 
                            Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
 
                            //  adjust sizeToDistribute value by subtracting auto definition min size
                            sizeToDistribute -= (tempDefinitions[i].MinSize);
                        }
 
                        for (; i < count; ++i)
                        { 
                            //  sanity check: no auto definitions allowed in this loop 
                            Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
 
                            double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinitions[i].PreferredSize);
                            if (newMinSize > tempDefinitions[i].MinSize) { tempDefinitions[i].UpdateMinSize(newMinSize); }
                            sizeToDistribute -= newMinSize;
                        } 

                        //  sanity check: requested size must all be distributed 
                        Debug.Assert(_IsZero(sizeToDistribute)); 
                    }
                    else if (requestedSize <= rangeMaxSize) 
                    {
                        //
                        //  requestedSize bigger than preferred size, but fit into max size of the range.
                        //  distribute according to the following logic: 
                        //  * do not distribute into auto definitions, if possible - they should continue to stay "tight";
                        //  * for all non-auto definitions distribute to euqi-size min sizes, without exceeding max size. 
                        // 
                        //  in order to achieve that, definitions are sorted in a way that all non-auto definitions
                        //  are last, then definitions follow ascending order with MaxSize as the key of sorting. 
                        //
                        double sizeToDistribute;
                        int i;
 
                        Array.Sort(tempDefinitions, 0, count, s_spanMaxDistributionOrderComparer);
                        for (i = 0, sizeToDistribute = requestedSize - rangePreferredSize; i < count - autoDefinitionsCount; ++i) 
                        { 
                            //  sanity check: no auto definitions allowed in this loop
                            Debug.Assert(!tempDefinitions[i].UserSize.IsAuto); 

                            double preferredSize = tempDefinitions[i].PreferredSize;
                            double newMinSize = preferredSize + sizeToDistribute / (count - autoDefinitionsCount - i);
                            tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache)); 
                            sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
                        } 
 
                        for (; i < count; ++i)
                        { 
                            //  sanity check: only auto definitions allowed in this loop
                            Debug.Assert(tempDefinitions[i].UserSize.IsAuto);

                            double preferredSize = tempDefinitions[i].MinSize; 
                            double newMinSize = preferredSize + sizeToDistribute / (count - i);
                            tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache)); 
                            sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize); 
                        }
 
                        //  sanity check: requested size must all be distributed
                        Debug.Assert(_IsZero(sizeToDistribute));
                    }
                    else 
                    {
                        // 
                        //  requestedSize bigger than max size of the range. 
                        //  distribute according to the following logic:
                        //  * for all definitions distribute to equi-size min sizes. 
                        //
                        double equalSize = requestedSize / count;

                        if (    equalSize < maxMaxSize 
                            &&  !_AreClose(equalSize, maxMaxSize)   )
                        { 
                            //  equi-size is less than maximum of maxSizes. 
                            //  in this case distribute so that smaller definitions grow faster than
                            //  bigger ones. 
                            double totalRemainingSize = maxMaxSize * count - rangeMaxSize;
                            double sizeToDistribute = requestedSize - rangeMaxSize;

                            //  sanity check: totalRemainingSize and sizeToDistribute must be real positive numbers 
                            Debug.Assert(   !double.IsInfinity(totalRemainingSize)
                                        &&  !DoubleUtil.IsNaN(totalRemainingSize) 
                                        &&  totalRemainingSize > 0 
                                        &&  !double.IsInfinity(sizeToDistribute)
                                        &&  !DoubleUtil.IsNaN(sizeToDistribute) 
                                        &&  sizeToDistribute > 0    );

                            for (int i = 0; i < count; ++i)
                            { 
                                double deltaSize = (maxMaxSize - tempDefinitions[i].SizeCache) * sizeToDistribute / totalRemainingSize;
                                tempDefinitions[i].UpdateMinSize(tempDefinitions[i].SizeCache + deltaSize); 
                            } 
                        }
                        else 
                        {
                            //
                            //  equi-size is greater or equal to maximum of max sizes.
                            //  all definitions receive equalSize as their mim sizes. 
                            //
                            for (int i = 0; i < count; ++i) 
                            { 
                                tempDefinitions[i].UpdateMinSize(equalSize);
                            } 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// Resolves Star's for given array of definitions.
        ///  
        /// Array of definitions to resolve stars.
        /// All available size.
        /// 
        /// Must initialize LayoutSize for all Star entries in given array of definitions. 
        /// 
        private void ResolveStar( 
            DefinitionBase[] definitions, 
            double availableSize)
        { 
            DefinitionBase[] tempDefinitions = TempDefinitions;
            int starDefinitionsCount = 0;
            double takenSize = 0;
 
            for (int i = 0; i < definitions.Length; ++i)
            { 
                switch (definitions[i].SizeType) 
                {
                    case (LayoutTimeSizeType.Auto): 
                        takenSize += definitions[i].MinSize;
                        break;
                    case (LayoutTimeSizeType.Pixel):
                        takenSize += definitions[i].MeasureSize; 
                        break;
                    case (LayoutTimeSizeType.Star): 
                        { 
                            tempDefinitions[starDefinitionsCount++] = definitions[i];
 
                            double starValue = definitions[i].UserSize.Value;

                            if (_IsZero(starValue))
                            { 
                                definitions[i].MeasureSize = 0;
                                definitions[i].SizeCache = 0; 
                            } 
                            else
                            { 
                                //  clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values
                                //  can be summed up without overflow
                                starValue = Math.Min(starValue, c_starClip);
 
                                //  Note: normalized star value is temporary cached into MeasureSize
                                definitions[i].MeasureSize = starValue; 
                                double maxSize             = Math.Max(definitions[i].MinSize, definitions[i].UserMaxSize); 
                                maxSize                    = Math.Min(maxSize, c_starClip);
                                definitions[i].SizeCache   = maxSize / starValue; 
                            }
                        }
                        break;
                } 
            }
 
            if (starDefinitionsCount > 0) 
            {
                Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer); 

                //  the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow...
                //  partial sum value is stored in each definition's SizeCache member.
                //  this way the algorithm guarantees (starValue <= definition.SizeCache) and thus 
                //  (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero.
                //  this is an important change from previous implementation where the following was possible: 
                //  ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... 
                double allStarWeights = 0;
                int i = starDefinitionsCount - 1; 
                do
                {
                    allStarWeights += tempDefinitions[i].MeasureSize;
                    tempDefinitions[i].SizeCache = allStarWeights; 
                } while (--i >= 0);
 
                i = 0; 
                do
                { 
                    double resolvedSize;
                    double starValue = tempDefinitions[i].MeasureSize;

                    if (_IsZero(starValue)) 
                    {
                        resolvedSize = tempDefinitions[i].MinSize; 
                    } 
                    else
                    { 
                        double userSize = Math.Max(availableSize - takenSize, 0.0) * (starValue / tempDefinitions[i].SizeCache);
                        resolvedSize    = Math.Min(userSize, tempDefinitions[i].UserMaxSize);
                        resolvedSize    = Math.Max(tempDefinitions[i].MinSize, resolvedSize);
                    } 

                    tempDefinitions[i].MeasureSize = resolvedSize; 
                    takenSize                     += resolvedSize; 
                } while (++i < starDefinitionsCount);
            } 
        }

        /// 
        /// Calculates desired size for given array of definitions. 
        /// 
        /// Array of definitions to use for calculations. 
        /// Desired size. 
        private double CalculateDesiredSize(
            DefinitionBase[] definitions) 
        {
            double desiredSize = 0;

            for (int i = 0; i < definitions.Length; ++i) 
            {
                desiredSize += definitions[i].MinSize; 
            } 

            return (desiredSize); 
        }

        /// 
        /// Calculates and sets final size for all definitions in the given array. 
        /// 
        /// Array of definitions to process. 
        /// Final size to lay out to. 
        private void SetFinalSize(
            DefinitionBase[] definitions, 
            double finalSize)
        {
            DefinitionBase[] tempDefinitions = TempDefinitions; //  temp array used to remember definitions indices
            int starDefinitionsCount = 0;                       //  traverses form the first entry up 
            int nonStarIndex = definitions.Length;              //  traverses from the last entry down
            double allPreferredArrangeSize = 0; 
 
            for (int i = 0; i < definitions.Length; ++i)
            { 
                //  if definition is shared then is cannot be star
                Debug.Assert(!definitions[i].IsShared || !definitions[i].UserSize.IsStar);

                if (definitions[i].UserSize.IsStar) 
                {
                    tempDefinitions[starDefinitionsCount++] = definitions[i]; 
 
                    double starValue = definitions[i].UserSize.Value;
 
                    if (_IsZero(starValue))
                    {
                        //  cach normilized star value temporary into MeasureSize
                        definitions[i].MeasureSize = 0; 
                        definitions[i].SizeCache = 0;
                    } 
                    else 
                    {
                        //  clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values 
                        //  can be summed up without overflow
                        starValue = Math.Min(starValue, c_starClip);

                        //  Note: normalized star value is temporary cached into MeasureSize 
                        definitions[i].MeasureSize = starValue;
                        double maxSize = Math.Max(definitions[i].MinSizeForArrange, definitions[i].UserMaxSize); 
                        maxSize = Math.Min(maxSize, c_starClip); 
                        definitions[i].SizeCache = maxSize / starValue;
                    } 
                }
                else
                {
                    tempDefinitions[--nonStarIndex] = definitions[i]; 

                    double userSize = 0; 
 
                    switch (definitions[i].UserSize.GridUnitType)
                    { 
                        case (GridUnitType.Pixel):
                            userSize = definitions[i].UserSize.Value;
                            break;
 
                        case (GridUnitType.Auto):
                            userSize = definitions[i].MinSizeForArrange; 
                            break; 
                    }
 
                    double userMaxSize;

                    if (definitions[i].IsShared)
                    { 
                        //  overriding userMaxSize effectively prevents squishy-ness.
                        //  this is a "solution" to avoid shared definitions from been sized to 
                        //  different final size at arrange time, if / when different grids receive 
                        //  different final sizes.
                        userMaxSize = userSize; 
                    }
                    else
                    {
                        userMaxSize = definitions[i].UserMaxSize; 
                    }
 
                    definitions[i].SizeCache = Math.Max(definitions[i].MinSizeForArrange, Math.Min(userSize, userMaxSize)); 
                    allPreferredArrangeSize += definitions[i].SizeCache;
                } 
            }

            //  indices should meet
            Debug.Assert(nonStarIndex == starDefinitionsCount); 

            if (starDefinitionsCount > 0) 
            { 
                Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer);
 
                //  the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow...
                //  partial sum value is stored in each definition's SizeCache member.
                //  this way the algorithm guarantees (starValue <= definition.SizeCache) and thus
                //  (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. 
                //  this is an important change from previous implementation where the following was possible:
                //  ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... 
                double allStarWeights = 0; 
                int i = starDefinitionsCount - 1;
                do 
                {
                    allStarWeights += tempDefinitions[i].MeasureSize;
                    tempDefinitions[i].SizeCache = allStarWeights;
                } while (--i >= 0); 

                i = 0; 
                do 
                {
                    double resolvedSize; 
                    double starValue = tempDefinitions[i].MeasureSize;

                    if (_IsZero(starValue))
                    { 
                        resolvedSize = tempDefinitions[i].MinSizeForArrange;
                    } 
                    else 
                    {
                        double userSize = Math.Max(finalSize - allPreferredArrangeSize, 0.0) * (starValue / tempDefinitions[i].SizeCache); 
                        resolvedSize    = Math.Min(userSize, tempDefinitions[i].UserMaxSize);
                        resolvedSize    = Math.Max(tempDefinitions[i].MinSizeForArrange, resolvedSize);
                    }
 
                    tempDefinitions[i].SizeCache = resolvedSize;
                    allPreferredArrangeSize     += resolvedSize; 
                } while (++i < starDefinitionsCount); 
            }
 
            if (    allPreferredArrangeSize > finalSize
                &&  !_AreClose(allPreferredArrangeSize, finalSize)  )
            {
                Array.Sort(tempDefinitions, 0, definitions.Length, s_distributionOrderComparer); 
                double sizeToDistribute = finalSize - allPreferredArrangeSize;
 
                for (int i = 0; i < definitions.Length; ++i) 
                {
                    double final = tempDefinitions[i].SizeCache + (sizeToDistribute / (definitions.Length - i)); 

                    final = Math.Max(final, tempDefinitions[i].MinSizeForArrange);
                    final = Math.Min(final, tempDefinitions[i].SizeCache);
                    sizeToDistribute -= (final - tempDefinitions[i].SizeCache); 
                    tempDefinitions[i].SizeCache = final;
                } 
            } 

            definitions[0].FinalOffset = 0.0; 
            for (int i = 0; i < definitions.Length; ++i)
            {
                definitions[(i + 1) % definitions.Length].FinalOffset = definitions[i].FinalOffset + definitions[i].SizeCache;
            } 
        }
 
        ///  
        /// Calculates final (aka arrange) size for given range.
        ///  
        /// Array of definitions to process.
        /// Start of the range.
        /// Number of items in the range.
        /// Final size. 
        private double GetFinalSizeForRange(
            DefinitionBase[] definitions, 
            int start, 
            int count)
        { 
            double size = 0;
            int i = start + count - 1;

            do 
            {
                size += definitions[i].SizeCache; 
            } while (--i >= start); 

            return (size); 
        }

        /// 
        /// Clears dirty state for the grid and its columns / rows 
        /// 
        private void SetValid() 
        { 
            ExtendedData extData = ExtData;
            if (extData != null) 
            {
//                for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid ();
//                for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid ();
 
                if (extData.TempDefinitions != null)
                { 
                    //  TempDefinitions has to be cleared to avoid "memory leaks" 
                    Array.Clear(extData.TempDefinitions, 0, Math.Max(DefinitionsU.Length, DefinitionsV.Length));
                    extData.TempDefinitions = null; 
                }
            }
        }
 
        /// 
        /// Returns true if ColumnDefinitions collection is not empty 
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeColumnDefinitions() 
        {
            ExtendedData extData = ExtData;
            return (    extData != null
                    &&  extData.ColumnDefinitions != null 
                    &&  extData.ColumnDefinitions.Count > 0   );
        } 
 
        /// 
        /// Returns true if RowDefinitions collection is not empty 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeRowDefinitions()
        { 
            ExtendedData extData = ExtData;
            return (    extData != null 
                    &&  extData.RowDefinitions != null 
                    &&  extData.RowDefinitions.Count > 0  );
        } 

        /// 
        /// Synchronized ShowGridLines property with the state of the grid's visual collection
        /// by adding / removing GridLinesRenderer visual. 
        /// Returns a reference to GridLinesRenderer visual or null.
        ///  
        private GridLinesRenderer EnsureGridLinesRenderer() 
        {
            // 
            //  synchronize the state
            //
            if (ShowGridLines && (_gridLinesRenderer == null))
            { 
                _gridLinesRenderer = new GridLinesRenderer();
                this.AddVisualChild(_gridLinesRenderer); 
            } 

            if ((!ShowGridLines) && (_gridLinesRenderer != null)) 
            {
                this.RemoveVisualChild(_gridLinesRenderer);
                _gridLinesRenderer = null;
            } 

            return (_gridLinesRenderer); 
        } 

        ///  
        /// SetFlags is used to set or unset one or multiple
        /// flags on the object.
        /// 
        private void SetFlags(bool value, Flags flags) 
        {
            _flags = value ? (_flags | flags) : (_flags & (~flags)); 
        } 

        ///  
        /// CheckFlagsAnd returns true if all the flags in the
        /// given bitmask are set on the object.
        /// 
        private bool CheckFlagsAnd(Flags flags) 
        {
            return ((_flags & flags) == flags); 
        } 

        ///  
        /// CheckFlagsOr returns true if at least one flag in the
        /// given bitmask is set.
        /// 
        ///  
        /// If no bits are set in the given bitmask, the method returns
        /// true. 
        ///  
        private bool CheckFlagsOr(Flags flags)
        { 
            return (flags == 0 || (_flags & flags) != 0);
        }

        ///  
        /// 
        ///  
        private static void OnShowGridLinesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            Grid grid = (Grid)d; 

            if (    grid.ExtData != null    // trivial grid is 1 by 1. there is no grid lines anyway
                &&  grid.ListenToNotifications)
            { 
                grid.InvalidateVisual();
            } 
 
            grid.SetFlags((bool) e.NewValue, Flags.ShowGridLinesPropertyValue);
        } 

        /// 
        /// 
        ///  
        private static void OnCellAttachedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            Visual child = d as Visual; 

            if (child != null) 
            {
                Grid grid = VisualTreeHelper.GetParent(child) as Grid;
                if (    grid != null
                    &&  grid.ExtData != null 
                    &&  grid.ListenToNotifications  )
                { 
                    grid.CellsStructureDirty = true; 
                    grid.InvalidateMeasure();
                } 
            }
        }

        ///  
        /// 
        ///  
        private static bool IsIntValueNotNegative(object value) 
        {
            return ((int)value >= 0); 
        }

        /// 
        ///  
        /// 
        private static bool IsIntValueGreaterThanZero(object value) 
        { 
            return ((int)value > 0);
        } 

        #endregion Private Methods

        //------------------------------------------------------ 
        //
        //  Private Properties 
        // 
        //-----------------------------------------------------
 
        #region Private Properties

        /// 
        /// Private version returning array of column definitions. 
        /// 
        private DefinitionBase[] DefinitionsU 
        { 
            get { return (ExtData.DefinitionsU); }
        } 

        /// 
        /// Private version returning array of row definitions.
        ///  
        private DefinitionBase[] DefinitionsV
        { 
            get { return (ExtData.DefinitionsV); } 
        }
 
        /// 
        /// Helper accessor to layout time array of definitions.
        /// 
        private DefinitionBase[] TempDefinitions 
        {
            get 
            { 
                ExtendedData extData = ExtData;
 
                if (extData.TempDefinitions == null)
                {
                    int requiredLength = Math.Max(DefinitionsU.Length, DefinitionsV.Length);
                    WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot); 
                    if (tempDefinitionsWeakRef == null)
                    { 
                        extData.TempDefinitions = new DefinitionBase[requiredLength * 2]; 
                        Thread.SetData(s_tempDefinitionsDataSlot, new WeakReference(extData.TempDefinitions));
                    } 
                    else
                    {
                        extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target;
                        if (    extData.TempDefinitions == null 
                            ||  extData.TempDefinitions.Length < requiredLength   )
                        { 
                            extData.TempDefinitions = new DefinitionBase[requiredLength * 2]; 
                            tempDefinitionsWeakRef.Target = extData.TempDefinitions;
                        } 
                    }
                }
                return (extData.TempDefinitions);
            } 
        }
 
        ///  
        /// Private version returning array of cells.
        ///  
        private CellCache[] PrivateCells
        {
            get { return (ExtData.CellCachesCollection); }
        } 

        ///  
        /// Convenience accessor to ValidCellsStructure bit flag. 
        /// 
        private bool CellsStructureDirty 
        {
            get { return (!CheckFlagsAnd(Flags.ValidCellsStructure)); }
            set { SetFlags(!value, Flags.ValidCellsStructure); }
        } 

        ///  
        /// Convenience accessor to ListenToNotifications bit flag. 
        /// 
        private bool ListenToNotifications 
        {
            get { return (CheckFlagsAnd(Flags.ListenToNotifications)); }
            set { SetFlags(value, Flags.ListenToNotifications); }
        } 

        ///  
        /// Convenience accessor to SizeToContentU bit flag. 
        /// 
        private bool SizeToContentU 
        {
            get { return (CheckFlagsAnd(Flags.SizeToContentU)); }
            set { SetFlags(value, Flags.SizeToContentU); }
        } 

        ///  
        /// Convenience accessor to SizeToContentV bit flag. 
        /// 
        private bool SizeToContentV 
        {
            get { return (CheckFlagsAnd(Flags.SizeToContentV)); }
            set { SetFlags(value, Flags.SizeToContentV); }
        } 

        ///  
        /// Convenience accessor to HasStarCellsU bit flag. 
        /// 
        private bool HasStarCellsU 
        {
            get { return (CheckFlagsAnd(Flags.HasStarCellsU)); }
            set { SetFlags(value, Flags.HasStarCellsU); }
        } 

        ///  
        /// Convenience accessor to HasStarCellsV bit flag. 
        /// 
        private bool HasStarCellsV 
        {
            get { return (CheckFlagsAnd(Flags.HasStarCellsV)); }
            set { SetFlags(value, Flags.HasStarCellsV); }
        } 

        ///  
        /// Convenience accessor to HasGroup3CellsInAutoRows bit flag. 
        /// 
        private bool HasGroup3CellsInAutoRows 
        {
            get { return (CheckFlagsAnd(Flags.HasGroup3CellsInAutoRows)); }
            set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
        } 

        ///  
        /// fp version of d == 0. 
        /// 
        /// Value to check. 
        /// true if d == 0.
        private static bool _IsZero(double d)
        {
            return (Math.Abs(d) < c_epsilon); 
        }
 
        ///  
        /// fp version of d1 == d2
        ///  
        /// First value to compare
        /// Second value to compare
        /// true if d1 == d2
        private static bool _AreClose(double d1, double d2) 
        {
            return (Math.Abs(d1 - d2) < c_epsilon); 
        } 

        ///  
        /// Returns reference to extended data bag.
        /// 
        private ExtendedData ExtData
        { 
            get { return (_data); }
        } 
 
        #endregion Private Properties
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 
        private ExtendedData _data;                             //  extended data instantiated on demand, for non-trivial case handling only
        private Flags _flags;                                   //  grid validity / property caches dirtiness flags 
        private GridLinesRenderer _gridLinesRenderer;
        #endregion Private Fields

        //----------------------------------------------------- 
        //
        //  Static Fields 
        // 
        //-----------------------------------------------------
 
        #region Static Fields
        private const double c_epsilon = 1e-5;                  //  used in fp calculations
        private const double c_starClip = 1e298;                //  used as maximum for clipping star values during normalization
        private static readonly LocalDataStoreSlot s_tempDefinitionsDataSlot = Thread.AllocateDataSlot(); 
        private static readonly IComparer s_spanPreferredDistributionOrderComparer = new SpanPreferredDistributionOrderComparer();
        private static readonly IComparer s_spanMaxDistributionOrderComparer = new SpanMaxDistributionOrderComparer(); 
        private static readonly IComparer s_starDistributionOrderComparer = new StarDistributionOrderComparer(); 
        private static readonly IComparer s_distributionOrderComparer = new DistributionOrderComparer();
        #endregion Static Fields 

        //------------------------------------------------------
        //
        //  Private Structures / Classes 
        //
        //----------------------------------------------------- 
 
        #region Private Structures Classes
 
        /// 
        /// Extended data instantiated on demand, when grid handles non-trivial case.
        /// 
        private class ExtendedData 
        {
            internal ColumnDefinitionCollection ColumnDefinitions;  //  collection of column definitions (logical tree support) 
            internal RowDefinitionCollection RowDefinitions;        //  collection of row definitions (logical tree support) 
            internal DefinitionBase[] DefinitionsU;                 //  collection of column definitions used during calc
            internal DefinitionBase[] DefinitionsV;                 //  collection of row definitions used during calc 
            internal CellCache[] CellCachesCollection;              //  backing store for logical children
            internal int CellGroup1;                                //  index of the first cell in first cell group
            internal int CellGroup2;                                //  index of the first cell in second cell group
            internal int CellGroup3;                                //  index of the first cell in third cell group 
            internal int CellGroup4;                                //  index of the first cell in forth cell group
            internal DefinitionBase[] TempDefinitions;              //  temporary array used during layout for various purposes 
                                                                    //  TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length) 
        }
 
        /// 
        /// Grid validity / property caches dirtiness flags
        /// 
        [System.Flags] 
        private enum Flags
        { 
            // 
            //  the foolowing flags let grid tracking dirtiness in more granular manner:
            //  * Valid???Structure flags indicate that elements were added or removed. 
            //  * Valid???Layout flags indicate that layout time portion of the information
            //    stored on the objects should be updated.
            //
            ValidDefinitionsUStructure              = 0x00000001, 
            ValidDefinitionsVStructure              = 0x00000002,
            ValidCellsStructure                     = 0x00000004, 
 
            //
            //  boolean properties state 
            //
            ShowGridLinesPropertyValue              = 0x00000100,   //  show grid lines ?

            // 
            //  boolean flags
            // 
            ListenToNotifications                   = 0x00001000,   //  "0" when all notifications are ignored 
            SizeToContentU                          = 0x00002000,   //  "1" if calculating to content in U direction
            SizeToContentV                          = 0x00004000,   //  "1" if calculating to content in V direction 
            HasStarCellsU                           = 0x00008000,   //  "1" if at least one cell belongs to a Star column
            HasStarCellsV                           = 0x00010000,   //  "1" if at least one cell belongs to a Star row
            HasGroup3CellsInAutoRows                = 0x00020000,   //  "1" if at least one cell of group 3 belongs to an Auto row
            MeasureOverrideInProgress               = 0x00040000,   //  "1" while in the context of Grid.MeasureOverride 
            ArrangeOverrideInProgress               = 0x00080000,   //  "1" while in the context of Grid.ArrangeOverride
        } 
 
        #endregion Private Structures Classes
 
        //------------------------------------------------------
        //
        //  Properties
        // 
        //------------------------------------------------------
 
        #region Properties 

        ///  
        /// ShowGridLines property. This property is used mostly
        /// for simplification of visual debuggig. When it is set
        /// to true grid lines are drawn to visualize location
        /// of grid lines. 
        /// 
        public static readonly DependencyProperty ShowGridLinesProperty = 
                DependencyProperty.Register( 
                      "ShowGridLines",
                      typeof(bool), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              false,
                              new PropertyChangedCallback(OnShowGridLinesPropertyChanged))); 

        ///  
        /// Column property. This is an attached property. 
        /// Grid defines Column property, so that it can be set
        /// on any element treated as a cell. Column property 
        /// specifies child's position with respect to columns.
        /// 
        /// 
        ///  Columns are 0 - based. In order to appear in first column, element 
        /// should have Column property set to 0. 
        ///  Default value for the property is 0.  
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty ColumnProperty = 
                DependencyProperty.RegisterAttached(
                      "Column",
                      typeof(int),
                      typeof(Grid), 
                      new FrameworkPropertyMetadata(
                              0, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)), 
                      new ValidateValueCallback(IsIntValueNotNegative));
 
        /// 
        /// Row property. This is an attached property.
        /// Grid defines Row, so that it can be set
        /// on any element treated as a cell. Row property 
        /// specifies child's position with respect to rows.
        ///  
        ///  Rows are 0 - based. In order to appear in first row, element 
        /// should have Row property set to 0. 
        ///  Default value for the property is 0.  
        /// 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty RowProperty = 
                DependencyProperty.RegisterAttached(
                      "Row", 
                      typeof(int), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata( 
                              0,
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueNotNegative));
 
        /// 
        /// ColumnSpan property. This is an attached property. 
        /// Grid defines ColumnSpan, so that it can be set 
        /// on any element treated as a cell. ColumnSpan property
        /// specifies child's width with respect to columns. 
        /// Example, ColumnSpan == 2 means that child will span across two columns.
        /// 
        /// 
        /// Default value for the property is 1. 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ColumnSpanProperty = 
                DependencyProperty.RegisterAttached(
                      "ColumnSpan", 
                      typeof(int),
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              1, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueGreaterThanZero)); 
 
        /// 
        /// RowSpan property. This is an attached property. 
        /// Grid defines RowSpan, so that it can be set
        /// on any element treated as a cell. RowSpan property
        /// specifies child's height with respect to row grid lines.
        /// Example, RowSpan == 3 means that child will span across three rows. 
        /// 
        ///  
        /// Default value for the property is 1. 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty RowSpanProperty =
                DependencyProperty.RegisterAttached(
                      "RowSpan",
                      typeof(int), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata( 
                              1, 
                              new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
                      new ValidateValueCallback(IsIntValueGreaterThanZero)); 


        /// 
        /// IsSharedSizeScope property marks scoping element for shared size. 
        /// 
        public static readonly DependencyProperty IsSharedSizeScopeProperty  = 
                DependencyProperty.RegisterAttached( 
                      "IsSharedSizeScope",
                      typeof(bool), 
                      typeof(Grid),
                      new FrameworkPropertyMetadata(
                              false,
                              new PropertyChangedCallback(DefinitionBase.OnIsSharedSizeScopePropertyChanged))); 

        #endregion Properties 
 
        //-----------------------------------------------------
        // 
        //  Internal Structures / Classes
        //
        //------------------------------------------------------
 
        #region Internal Structures Classes
 
        ///  
        /// LayoutTimeSizeType is used internally and reflects layout-time size type.
        ///  
        [System.Flags]
        internal enum LayoutTimeSizeType : byte
        {
            None        = 0x00, 
            Pixel       = 0x01,
            Auto        = 0x02, 
            Star        = 0x04, 
        }
 
        #endregion Internal Structures Classes

        //-----------------------------------------------------
        // 
        //  Private Structures / Classes
        // 
        //----------------------------------------------------- 

        #region Private Structures Classes 

        /// 
        /// CellCache stored calculated values of
        /// 1. attached cell positioning properties; 
        /// 2. size type;
        /// 3. index of a next cell in the group; 
        ///  
        private struct CellCache
        { 
            internal int ColumnIndex;
            internal int RowIndex;
            internal int ColumnSpan;
            internal int RowSpan; 
            internal LayoutTimeSizeType SizeTypeU;
            internal LayoutTimeSizeType SizeTypeV; 
            internal int Next; 
            internal bool IsStarU { get { return ((SizeTypeU & LayoutTimeSizeType.Star) != 0); } }
            internal bool IsAutoU { get { return ((SizeTypeU & LayoutTimeSizeType.Auto) != 0); } } 
            internal bool IsStarV { get { return ((SizeTypeV & LayoutTimeSizeType.Star) != 0); } }
            internal bool IsAutoV { get { return ((SizeTypeV & LayoutTimeSizeType.Auto) != 0); } }
        }
 
        /// 
        /// Helper class for representing a key for a span in hashtable. 
        ///  
        private class SpanKey
        { 
            /// 
            /// Constructor.
            /// 
            /// Starting index of the span. 
            /// Span count.
            /// true for columns; false for rows. 
            internal SpanKey(int start, int count, bool u) 
            {
                _start = start; 
                _count = count;
                _u = u;
            }
 
            /// 
            ///  
            ///  
            public override int GetHashCode()
            { 
                int hash = (_start ^ (_count << 2));

                if (_u) hash &= 0x7ffffff;
                else    hash |= 0x8000000; 

                return (hash); 
            } 

            ///  
            /// 
            /// 
            public override bool Equals(object obj)
            { 
                SpanKey sk = obj as SpanKey;
                return (    sk != null 
                        &&  sk._start == _start 
                        &&  sk._count == _count
                        &&  sk._u == _u ); 
            }

            /// 
            /// Returns start index of the span. 
            /// 
            internal int Start { get { return (_start); } } 
 
            /// 
            /// Returns span count. 
            /// 
            internal int Count { get { return (_count); } }

            ///  
            /// Returns true if this is a column span.
            /// false if this is a row span. 
            ///  
            internal bool U { get { return (_u); } }
 
            private int _start;
            private int _count;
            private bool _u;
        } 

        ///  
        /// SpanPreferredDistributionOrderComparer. 
        /// 
        private class SpanPreferredDistributionOrderComparer : IComparer 
        {
            public int Compare(object x, object y)
            {
                if (x == y) return (0); 

                DefinitionBase definitionX = (DefinitionBase)x; 
                DefinitionBase definitionY = (DefinitionBase)y; 

                if (definitionX.UserSize.IsAuto) 
                {
                    if (definitionY.UserSize.IsAuto)    return ((definitionX.MinSize > definitionY.MinSize) ? 1 : -1);
                    return (-1);
                } 
                else
                { 
                    if (!definitionY.UserSize.IsAuto)   return ((definitionX.PreferredSize > definitionY.PreferredSize) ? 1 : -1); 
                    return (1);
                } 
            }
        }

        ///  
        /// SpanMaxDistributionOrderComparer.
        ///  
        private class SpanMaxDistributionOrderComparer : IComparer 
        {
            public int Compare(object x, object y) 
            {
                if (x == y) return (0);

                DefinitionBase definitionX = (DefinitionBase)x; 
                DefinitionBase definitionY = (DefinitionBase)y;
 
                if (definitionX.UserSize.IsAuto) 
                {
                    if (definitionY.UserSize.IsAuto)    return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1); 
                    return (1);
                }
                else
                { 
                    if (!definitionY.UserSize.IsAuto)   return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1);
                    return (-1); 
                } 
            }
        } 

        /// 
        /// StarDistributionOrderComparer.
        ///  
        private class StarDistributionOrderComparer : IComparer
        { 
            public int Compare(object x, object y) 
            {
                if (x == y) return (0); 

                DefinitionBase definitionX = (DefinitionBase)x;
                DefinitionBase definitionY = (DefinitionBase)y;
                return ((definitionX.SizeCache > definitionY.SizeCache) ? 1 : -1); 
            }
        } 
 
        /// 
        /// DistributionOrderComparer. 
        /// 
        private class DistributionOrderComparer: IComparer
        {
            public int Compare(object x, object y) 
            {
                if (x == y) return (0); 
 
                DefinitionBase definitionX = (DefinitionBase)x;
                DefinitionBase definitionY = (DefinitionBase)y; 
                return ((definitionX.SizeCache - definitionX.MinSizeForArrange) > (definitionY.SizeCache - definitionY.MinSizeForArrange) ? 1 : -1);
            }
        }
 
        /// 
        /// Implementation of a simple enumerator of grid's logical children 
        ///  
        private class GridChildrenCollectionEnumeratorSimple : IEnumerator
        { 
            internal GridChildrenCollectionEnumeratorSimple(Grid grid, bool includeChildren)
            {
                Debug.Assert(grid != null);
                _currentEnumerator = -1; 
                _enumerator0 = new ColumnDefinitionCollection.Enumerator(grid.ExtData != null ? grid.ExtData.ColumnDefinitions : null);
                _enumerator1 = new RowDefinitionCollection.Enumerator(grid.ExtData != null ? grid.ExtData.RowDefinitions : null); 
                // GridLineRenderer is NOT included into this enumerator. 
                _enumerator2Index = 0;
                if (includeChildren) 
                {
                    _enumerator2Collection = grid.Children;
                    _enumerator2Count = _enumerator2Collection.Count;
                } 
                else
                { 
                    _enumerator2Collection = null; 
                    _enumerator2Count = 0;
                } 
            }

            public bool MoveNext()
            { 
                while (_currentEnumerator < 3)
                { 
                    if (_currentEnumerator >= 0) 
                    {
                        switch (_currentEnumerator) 
                        {
                            case (0): if (_enumerator0.MoveNext()) { _currentChild = _enumerator0.Current; return (true); } break;
                            case (1): if (_enumerator1.MoveNext()) { _currentChild = _enumerator1.Current; return (true); } break;
                            case (2): if (_enumerator2Index < _enumerator2Count) 
                                      {
                                          _currentChild = _enumerator2Collection[_enumerator2Index]; 
                                          _enumerator2Index++; 
                                          return (true);
                                      } 
                                      break;
                        }
                    }
                    _currentEnumerator++; 
                }
                return (false); 
            } 

            public Object Current 
            {
                get
                {
                    if (_currentEnumerator == -1) 
                    {
                        #pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception 
                        throw new InvalidOperationException(SR.Get(SRID.EnumeratorNotStarted)); 
                    }
                    if (_currentEnumerator >= 3) 
                    {
                        #pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception
                        throw new InvalidOperationException(SR.Get(SRID.EnumeratorReachedEnd));
                    } 

                    //  assert below is not true anymore since UIElementCollection allowes for null children 
                    //Debug.Assert(_currentChild != null); 
                    return (_currentChild);
                } 
            }

            public void Reset()
            { 
                _currentEnumerator = -1;
                _currentChild = null; 
                _enumerator0.Reset(); 
                _enumerator1.Reset();
                _enumerator2Index = 0; 
            }

            private int _currentEnumerator;
            private Object _currentChild; 
            private ColumnDefinitionCollection.Enumerator _enumerator0;
            private RowDefinitionCollection.Enumerator _enumerator1; 
            private UIElementCollection _enumerator2Collection; 
            private int _enumerator2Index;
            private int _enumerator2Count; 
        }

        /// 
        /// Helper to render grid lines. 
        /// 
        internal class GridLinesRenderer : DrawingVisual 
        { 
            /// 
            /// Static initialization 
            /// 
            static GridLinesRenderer()
            {
                s_oddDashPen = new Pen(Brushes.Blue, c_penWidth); 
                DoubleCollection oddDashArray = new DoubleCollection();
                oddDashArray.Add(c_dashLength); 
                oddDashArray.Add(c_dashLength); 
                s_oddDashPen.DashStyle = new DashStyle(oddDashArray, 0);
                s_oddDashPen.DashCap = PenLineCap.Flat; 
                s_oddDashPen.Freeze();

                s_evenDashPen = new Pen(Brushes.Yellow, c_penWidth);
                DoubleCollection evenDashArray = new DoubleCollection(); 
                evenDashArray.Add(c_dashLength);
                evenDashArray.Add(c_dashLength); 
                s_evenDashPen.DashStyle = new DashStyle(evenDashArray, c_dashLength); 
                s_evenDashPen.DashCap = PenLineCap.Flat;
                s_evenDashPen.Freeze(); 
            }

            /// 
            /// UpdateRenderBounds. 
            /// 
            /// Size of render bounds 
            internal void UpdateRenderBounds(Size boundsSize) 
            {
                using (DrawingContext drawingContext = RenderOpen()) 
                {
                    Grid grid = VisualTreeHelper.GetParent(this) as Grid;
                    if (    grid == null
                        ||  grid.ShowGridLines == false ) 
                    {
                        return; 
                    } 

                    for (int i = 1; i < grid.DefinitionsU.Length; ++i) 
                    {
                        DrawGridLine(
                            drawingContext,
                            grid.DefinitionsU[i].FinalOffset, 0.0, 
                            grid.DefinitionsU[i].FinalOffset, boundsSize.Height);
                    } 
 
                    for (int i = 1; i < grid.DefinitionsV.Length; ++i)
                    { 
                        DrawGridLine(
                            drawingContext,
                            0.0, grid.DefinitionsV[i].FinalOffset,
                            boundsSize.Width, grid.DefinitionsV[i].FinalOffset); 
                    }
                } 
            } 

            ///  
            /// Draw single hi-contrast line.
            /// 
            private static void DrawGridLine(
                DrawingContext drawingContext, 
                double startX,
                double startY, 
                double endX, 
                double endY)
            { 
                Point start = new Point(startX, startY);
                Point end = new Point(endX, endY);
                drawingContext.DrawLine(s_oddDashPen, start, end);
                drawingContext.DrawLine(s_evenDashPen, start, end); 
            }
 
            private const double c_dashLength = 4.0;    // 
            private const double c_penWidth = 1.0;      //
            private static readonly Pen s_oddDashPen;   //  first pen to draw dash 
            private static readonly Pen s_evenDashPen;  //  second pen to draw dash
            private static readonly Point c_zeroPoint = new Point(0, 0);
        }
 
        #endregion Private Structures Classes
 
        //----------------------------------------------------- 
        //
        //  Extended debugging for grid 
        //
        //------------------------------------------------------

#if GRIDPARANOIA 
        private static double _performanceFrequency;
        private static readonly bool _performanceFrequencyInitialized = InitializePerformanceFrequency(); 
 
        //CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity, System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); 

        //CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity, System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out long lpFrequency);
 
        private static double CostInMilliseconds(long count)
        { 
            return ((double)count / _performanceFrequency); 
        }
 
        private static long Cost(long startCount, long endCount)
        {
            long l = endCount - startCount;
            if (l < 0)  { l += long.MaxValue;   } 
            return (l);
        } 
 
        private static bool InitializePerformanceFrequency()
        { 
            long l;
            QueryPerformanceFrequency(out l);
            _performanceFrequency = (double)l * 0.001;
            return (true); 
        }
 
        private struct Counter 
        {
            internal long   Start; 
            internal long   Total;
            internal int    Calls;
        }
 
        private Counter[] _counters;
        private bool _hasNewCounterInfo; 
#endif // GRIDPARANOIA 

        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        // 
        internal override int EffectiveValuesInitialSize
        { 
            get { return 9; } 
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void EnterCounterScope(Counters scopeCounter)
        {
            #if GRIDPARANOIA 
            if (ID == "CountThis")
            { 
                if (_counters == null) 
                {
                    _counters = new Counter[(int)Counters.Count]; 
                }
                ExitCounterScope(Counters.Default);
                EnterCounter(scopeCounter);
            } 
            else
            { 
                _counters = null; 
            }
            #endif // GRIDPARANOIA 
        }

        [Conditional("GRIDPARANOIA")]
        internal void ExitCounterScope(Counters scopeCounter) 
        {
            #if GRIDPARANOIA 
            if (_counters != null) 
            {
                if (scopeCounter != Counters.Default) 
                {
                    ExitCounter(scopeCounter);
                }
 
                if (_hasNewCounterInfo)
                { 
                    string NFormat = "F6"; 
                    Console.WriteLine(
                                "\ncounter name          | total t (ms)  | # of calls    | per call t (ms)" 
                            +   "\n----------------------+---------------+---------------+----------------------" );

                    for (int i = 0; i < _counters.Length; ++i)
                    { 
                        if (_counters[i].Calls > 0)
                        { 
                            Counters counter = (Counters)i; 
                            double total = CostInMilliseconds(_counters[i].Total);
                            double single = total / _counters[i].Calls; 
                            string counterName = counter.ToString();
                            string separator;

                            if (counterName.Length < 8)         { separator = "\t\t\t";  } 
                            else if (counterName.Length < 16)   { separator = "\t\t";    }
                            else                                { separator = "\t";      } 
 
                            Console.WriteLine(
                                    counter.ToString() + separator 
                                +   total.ToString(NFormat) + "\t"
                                +   _counters[i].Calls + "\t\t"
                                +   single.ToString(NFormat));
 
                            _counters[i] = new Counter();
                        } 
                    } 
                }
                _hasNewCounterInfo = false; 
            }
            #endif // GRIDPARANOIA
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void EnterCounter(Counters counter) 
        { 
            #if GRIDPARANOIA
            if (_counters != null) 
            {
                Debug.Assert((int)counter < _counters.Length);

                int i = (int)counter; 
                QueryPerformanceCounter(out _counters[i].Start);
            } 
            #endif // GRIDPARANOIA 
        }
 
        [Conditional("GRIDPARANOIA")]
        internal void ExitCounter(Counters counter)
        {
            #if GRIDPARANOIA 
            if (_counters != null)
            { 
                Debug.Assert((int)counter < _counters.Length); 

                int i = (int)counter; 
                long l;
                QueryPerformanceCounter(out l);
                l = Cost(_counters[i].Start, l);
                _counters[i].Total += l; 
                _counters[i].Calls++;
                _hasNewCounterInfo = true; 
            } 
            #endif // GRIDPARANOIA
        } 

        internal enum Counters : int
        {
            Default = -1, 

            MeasureOverride, 
            _ValidateColsStructure, 
            _ValidateRowsStructure,
            _ValidateCells, 
            _MeasureCell,
            __MeasureChild,
            _CalculateDesiredSize,
 
            ArrangeOverride,
            _SetFinalSize, 
            _ArrangeChildHelper2, 
            _PositionCell,
 
            Count,
        }
    }
} 

 
 


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

                        

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