Grid.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / Grid.cs / 1 / Grid.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Grid implementation. 
//
// Specs 
//      Grid : [....]/layout/Specs/Grid.mht
//      Size Sharing: [....]/layout/Specs/Size%20Information%20Sharing.doc
//
// Misc 
//      Grid Tutorial: [....]/layout/Documentation%20and%20Tutorials/Grid%20Tutorial.mht
// 
// History: 
//  09/24/2003 : [....] - Created (in griddy prototype branch);
//  10/27/2003 : [....] - Ported from griddy prototype branch; 
//  01/20/2004 : [....] - 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)
                        { 
                            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)
            { 
                child.Measure(new Size(cellMeasureWidth, cellMeasureHeight)); 
            }
            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