private bool SizeGrid(PrimarySecondaryLayout layout, GridLength secondaryUIElementSize)
        {
            var mustInvalidate = false;

            var star = new GridLength(1, GridUnitType.Star);  // Standard measurement used repeatedly below
            var auto = new GridLength(1, GridUnitType.Auto);  // Standard measurement used repeatedly below
            var zero = new GridLength(0, GridUnitType.Pixel); // Standard measurement used repeatedly below

            switch (layout)
            {
            case PrimarySecondaryLayout.PrimaryLeftSecondaryRight:
                mustInvalidate = SetColumnWidth(0, star, false);
                mustInvalidate = SetColumnWidth(1, new GridLength(UIElementSpacing), mustInvalidate);
                mustInvalidate = SetColumnWidth(2, secondaryUIElementSize, mustInvalidate);
                mustInvalidate = SetRowHeight(0, star, mustInvalidate);
                mustInvalidate = SetRowHeight(1, zero, mustInvalidate);
                mustInvalidate = SetRowHeight(2, zero, mustInvalidate);
                break;

            case PrimarySecondaryLayout.SecondaryLeftPrimaryRight:
                mustInvalidate = SetColumnWidth(0, secondaryUIElementSize, false);
                mustInvalidate = SetColumnWidth(1, new GridLength(UIElementSpacing), mustInvalidate);
                mustInvalidate = SetColumnWidth(2, star, mustInvalidate);
                mustInvalidate = SetRowHeight(0, star, mustInvalidate);
                mustInvalidate = SetRowHeight(1, zero, mustInvalidate);
                mustInvalidate = SetRowHeight(2, zero, mustInvalidate);
                break;

            case PrimarySecondaryLayout.PrimaryTopSecondaryBottom:
                mustInvalidate = SetRowHeight(0, star, false);
                mustInvalidate = SetRowHeight(1, new GridLength(UIElementSpacing), mustInvalidate);
                mustInvalidate = SetRowHeight(2, auto, mustInvalidate);
                mustInvalidate = SetColumnWidth(0, star, mustInvalidate);
                mustInvalidate = SetColumnWidth(1, zero, mustInvalidate);
                mustInvalidate = SetColumnWidth(2, zero, mustInvalidate);
                break;

            case PrimarySecondaryLayout.SecondaryTopPrimaryBottom:
                mustInvalidate = SetRowHeight(0, auto, false);
                mustInvalidate = SetRowHeight(1, new GridLength(UIElementSpacing), mustInvalidate);
                mustInvalidate = SetRowHeight(2, star, mustInvalidate);
                mustInvalidate = SetColumnWidth(0, star, mustInvalidate);
                mustInvalidate = SetColumnWidth(1, zero, mustInvalidate);
                mustInvalidate = SetColumnWidth(2, zero, mustInvalidate);
                break;
            }
            return(mustInvalidate);
        }
        /// <summary>
        /// Assigns the elements.
        /// </summary>
        /// <param name="layout">The layout.</param>
        /// <param name="primary">The primary.</param>
        /// <param name="secondary">The secondary.</param>
        /// <param name="mustInvalidate">if set to <c>true</c> [must invalidate].</param>
        /// <returns>True if successful</returns>
        protected virtual bool AssignElements(PrimarySecondaryLayout layout, UIElement primary, IEnumerable <UIElement> secondary, bool mustInvalidate)
        {
            switch (layout)
            {
            case PrimarySecondaryLayout.PrimaryLeftSecondaryRight:
                mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
                mustInvalidate = AssignRow(primary, 0, mustInvalidate);
                foreach (var element in secondary)
                {
                    mustInvalidate = AssignColumn(element, 2, mustInvalidate);
                    mustInvalidate = AssignRow(element, 0, mustInvalidate);
                }
                break;

            case PrimarySecondaryLayout.SecondaryLeftPrimaryRight:
                mustInvalidate = AssignColumn(primary, 2, mustInvalidate);
                mustInvalidate = AssignRow(primary, 0, mustInvalidate);
                foreach (var element in secondary)
                {
                    mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                    mustInvalidate = AssignRow(element, 0, mustInvalidate);
                }
                break;

            case PrimarySecondaryLayout.PrimaryTopSecondaryBottom:
                mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
                mustInvalidate = AssignRow(primary, 0, mustInvalidate);
                foreach (var element in secondary)
                {
                    mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                    mustInvalidate = AssignRow(element, 2, mustInvalidate);
                }
                break;

            case PrimarySecondaryLayout.SecondaryTopPrimaryBottom:
                mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
                mustInvalidate = AssignRow(primary, 2, mustInvalidate);
                foreach (var element in secondary)
                {
                    mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                    mustInvalidate = AssignRow(element, 0, mustInvalidate);
                }
                break;
            }
            return(mustInvalidate);
        }
        /// <summary>
        /// Assigns the elements.
        /// </summary>
        /// <param name="layout">The layout.</param>
        /// <param name="primary">The primary.</param>
        /// <param name="secondary">The secondary.</param>
        /// <param name="mustInvalidate">if set to <c>true</c> [must invalidate].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
        protected override bool AssignElements(PrimarySecondaryLayout layout, UIElement primary, IEnumerable <UIElement> secondary, bool mustInvalidate)
        {
            var result = base.AssignElements(layout, primary, secondary, mustInvalidate);

            var element1 = primary as FrameworkElement;

            if (element1 != null)
            {
                element1.Margin = PrimaryElementMargin;
            }

            var element2 = secondary.FirstOrDefault() as FrameworkElement;

            if (element2 != null)
            {
                element2.Margin = SecondaryElementMargin;
            }

            return(result);
        }
        /// <summary>
        /// Assigns the elements.
        /// </summary>
        /// <param name="layout">The layout.</param>
        /// <param name="primary">The primary.</param>
        /// <param name="secondary">The secondary.</param>
        /// <param name="mustInvalidate">if set to <c>true</c> [must invalidate].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
        protected override bool AssignElements(PrimarySecondaryLayout layout, UIElement primary, IEnumerable<UIElement> secondary, bool mustInvalidate)
        {
            var result = base.AssignElements(layout, primary, secondary, mustInvalidate);

            var element1 = primary as FrameworkElement;
            if (element1 != null) element1.Margin = PrimaryElementMargin;

            var element2 = secondary.FirstOrDefault() as FrameworkElement;
            if (element2 != null) element2.Margin = SecondaryElementMargin;

            return result;
        }
        /// <summary>
        /// Measures the children of a <see cref="T:System.Windows.Controls.Grid" /> in anticipation of arranging them during the <see cref="M:System.Windows.Controls.Grid.ArrangeOverride(System.Windows.Size)" /> pass.
        /// </summary>
        /// <param name="constraint">Indicates an upper limit size that should not be exceeded.</param>
        /// <returns><see cref="T:System.Windows.Size" /> that represents the required size to arrange child content.</returns>
        protected override Size MeasureOverride(Size constraint)
        {
            var noMargin = new Thickness();

            foreach (var child in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed))
            {
                var element = child as FrameworkElement;
                if (element == null)
                {
                    continue;
                }
                var mode = SimpleView.GetUIElementType(element);
                if (mode == UIElementTypes.Primary)
                {
                    var localMargin = PrimaryUIElementMargin;
                    if (localMargin != noMargin && element.Margin != localMargin)
                    {
                        element.Margin = localMargin;
                    }
                }
                else if (mode == UIElementTypes.Secondary)
                {
                    var localMargin = SecondaryUIElementMargin;
                    if (localMargin != noMargin && element.Margin != localMargin)
                    {
                        element.Margin = localMargin;
                    }
                }
            }

            var size = base.MeasureOverride(constraint);

            bool mustInvalidate; // Used to potentially trigger a secondary measure pass
            var  secondaryElementVisible = true;

            // We find the tallest secondary element. If it is taller than the threshold, we switch to horizontal layout
            var maxHeight = 0d;

            foreach (var element in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed))
            {
                var type = SimpleView.GetUIElementType(element);
                if (type == UIElementTypes.Secondary)
                {
                    if (element.Visibility != Visibility.Visible)
                    {
                        secondaryElementVisible = false;
                        maxHeight = 0;
                    }
                    else
                    {
                        maxHeight = Math.Max(element.DesiredSize.Height, maxHeight);
                    }
                }
            }

            if (maxHeight > SecondaryUIElementAlignmentChangeSize)
            {
                // Going to left/right
                CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryLeftPrimaryRight : PrimarySecondaryLayout.PrimaryLeftSecondaryRight;
                mustInvalidate   = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d));

                UIElement primary   = null;
                var       secondary = new List <UIElement>();

                // We need to assign children to columns
                foreach (var child in Children)
                {
                    var element = child as UIElement;
                    if (element == null)
                    {
                        continue;
                    }
                    var type = SimpleView.GetUIElementType(element);
                    if (type == UIElementTypes.Secondary)
                    {
                        secondary.Add(element);
                    }
                    else
                    {
                        primary = element;
                    }
                }
                mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate);
            }
            else
            {
                // This is a top/bottom layout
                CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryTopPrimaryBottom : PrimarySecondaryLayout.PrimaryTopSecondaryBottom;
                mustInvalidate   = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d));

                UIElement primary   = null;
                var       secondary = new List <UIElement>();

                // We need to assign children to rows
                foreach (var element in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed))
                {
                    var type = SimpleView.GetUIElementType(element);
                    if (type == UIElementTypes.Secondary)
                    {
                        secondary.Add(element);
                    }
                    else
                    {
                        primary = element;
                    }
                }
                mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate);
            }

            if (maxHeight > 0 && mustInvalidate)
            {
                // Need to run all this one more time to make sure everything got picked up right
                MeasureOverride(constraint);
                InvalidateVisual();
            }

            return(size);
        }
        private bool SizeGrid(PrimarySecondaryLayout layout, GridLength secondaryUIElementSize)
        {
            var mustInvalidate = false;

            var star = new GridLength(1, GridUnitType.Star); // Standard measurement used repeatedly below
            var auto = new GridLength(1, GridUnitType.Auto); // Standard measurement used repeatedly below
            var zero = new GridLength(0, GridUnitType.Pixel); // Standard measurement used repeatedly below

            switch (layout)
            {
                case PrimarySecondaryLayout.PrimaryLeftSecondaryRight:
                    mustInvalidate = SetColumnWidth(0, star, mustInvalidate);
                    mustInvalidate = SetColumnWidth(1, new GridLength(UIElementSpacing), mustInvalidate);
                    mustInvalidate = SetColumnWidth(2, secondaryUIElementSize, mustInvalidate);
                    mustInvalidate = SetRowHeight(0, star, mustInvalidate);
                    mustInvalidate = SetRowHeight(1, zero, mustInvalidate);
                    mustInvalidate = SetRowHeight(2, zero, mustInvalidate);
                    break;
                case PrimarySecondaryLayout.SecondaryLeftPrimaryRight:
                    mustInvalidate = SetColumnWidth(0, secondaryUIElementSize, mustInvalidate);
                    mustInvalidate = SetColumnWidth(1, new GridLength(UIElementSpacing), mustInvalidate);
                    mustInvalidate = SetColumnWidth(2, star, mustInvalidate);
                    mustInvalidate = SetRowHeight(0, star, mustInvalidate);
                    mustInvalidate = SetRowHeight(1, zero, mustInvalidate);
                    mustInvalidate = SetRowHeight(2, zero, mustInvalidate);
                    break;
                case PrimarySecondaryLayout.PrimaryTopSecondaryBottom:
                    mustInvalidate = SetRowHeight(0, star, mustInvalidate);
                    mustInvalidate = SetRowHeight(1, new GridLength(UIElementSpacing), mustInvalidate);
                    mustInvalidate = SetRowHeight(2, auto, mustInvalidate);
                    mustInvalidate = SetColumnWidth(0, star, mustInvalidate);
                    mustInvalidate = SetColumnWidth(1, zero, mustInvalidate);
                    mustInvalidate = SetColumnWidth(2, zero, mustInvalidate);
                    break;
                case PrimarySecondaryLayout.SecondaryTopPrimaryBottom:
                    mustInvalidate = SetRowHeight(0, auto, mustInvalidate);
                    mustInvalidate = SetRowHeight(1, new GridLength(UIElementSpacing), mustInvalidate);
                    mustInvalidate = SetRowHeight(2, star, mustInvalidate);
                    mustInvalidate = SetColumnWidth(0, star, mustInvalidate);
                    mustInvalidate = SetColumnWidth(1, zero, mustInvalidate);
                    mustInvalidate = SetColumnWidth(2, zero, mustInvalidate);
                    break;
            }
            return mustInvalidate;
        }
        /// <summary>
        /// Measures the children of a <see cref="T:System.Windows.Controls.Grid" /> in anticipation of arranging them during the <see cref="M:System.Windows.Controls.Grid.ArrangeOverride(System.Windows.Size)" /> pass.
        /// </summary>
        /// <param name="constraint">Indicates an upper limit size that should not be exceeded.</param>
        /// <returns><see cref="T:System.Windows.Size" /> that represents the required size to arrange child content.</returns>
        protected override Size MeasureOverride(Size constraint)
        {
            var noMargin = new Thickness();
            foreach (var child in Children)
            {
                var element = child as FrameworkElement;
                if (element != null)
                {
                    var mode = SimpleView.GetUIElementType(element);
                    if (mode == UIElementTypes.Primary)
                    {
                        var localMargin = PrimaryUIElementMargin;
                        if (localMargin != noMargin && element.Margin != localMargin)
                            element.Margin = localMargin;
                    }
                    else if (mode == UIElementTypes.Secondary)
                    {
                        var localMargin = SecondaryUIElementMargin;
                        if (localMargin != noMargin && element.Margin != localMargin)
                            element.Margin = localMargin;
                    }
                }
            }

            var size = base.MeasureOverride(constraint);

            var mustInvalidate = false; // Used to potentially trigger a secondary measure pass
            var secondaryElementVisible = true;

            // We find the tallest secondary element. If it is taller than the threshold, we switch to horizontal layout
            double maxHeight = 0;
            foreach (var child in Children)
            {
                var element = child as UIElement;
                if (element != null)
                {
                    var type = SimpleView.GetUIElementType(element);
                    if (type == UIElementTypes.Secondary)
                        if (element.Visibility != Visibility.Visible)
                        {
                            secondaryElementVisible = false;
                            maxHeight = 0;
                        }
                        else
                            maxHeight = Math.Max(element.DesiredSize.Height, maxHeight);
                }
            }

            if (maxHeight > SecondaryUIElementAlignmentChangeSize)
            {
                // Going to left/right
                CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryLeftPrimaryRight : PrimarySecondaryLayout.PrimaryLeftSecondaryRight;
                mustInvalidate = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d));

                UIElement primary = null;
                var secondary = new List<UIElement>();

                // We need to assign children to columns
                foreach (var child in Children)
                {
                    var element = child as UIElement;
                    if (element != null)
                    {
                        var type = SimpleView.GetUIElementType(element);
                        if (type == UIElementTypes.Secondary) secondary.Add(element);
                        else primary = element;
                    }
                }
                mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate);
            }
            else
            {
                // This is a top/bottom layout
                CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryTopPrimaryBottom : PrimarySecondaryLayout.PrimaryTopSecondaryBottom;
                mustInvalidate = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d));

                UIElement primary = null;
                var secondary = new List<UIElement>();

                // We need to assign children to rows
                foreach (var child in Children)
                {
                    var element = child as UIElement;
                    if (element != null)
                    {
                        var type = SimpleView.GetUIElementType(element);
                        if (type == UIElementTypes.Secondary) secondary.Add(element);
                        else primary = element;
                    }
                }
                mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate);
            }

            if (maxHeight > 0 && mustInvalidate)
            {
                // Need to run all this one more time to make sure everything got picked up right
                MeasureOverride(constraint);
                InvalidateVisual();
            }

            return size;
        }
 /// <summary>
 /// Assigns the elements.
 /// </summary>
 /// <param name="layout">The layout.</param>
 /// <param name="primary">The primary.</param>
 /// <param name="secondary">The secondary.</param>
 /// <param name="mustInvalidate">if set to <c>true</c> [must invalidate].</param>
 /// <returns>True if successful</returns>
 protected virtual bool AssignElements(PrimarySecondaryLayout layout, UIElement primary, IEnumerable<UIElement> secondary, bool mustInvalidate)
 {
     switch (layout)
     {
         case PrimarySecondaryLayout.PrimaryLeftSecondaryRight:
             mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
             mustInvalidate = AssignRow(primary, 0, mustInvalidate);
             foreach (var element in secondary)
             {
                 mustInvalidate = AssignColumn(element, 2, mustInvalidate);
                 mustInvalidate = AssignRow(element, 0, mustInvalidate);
             }
             break;
         case PrimarySecondaryLayout.SecondaryLeftPrimaryRight:
             mustInvalidate = AssignColumn(primary, 2, mustInvalidate);
             mustInvalidate = AssignRow(primary, 0, mustInvalidate);
             foreach (var element in secondary)
             {
                 mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                 mustInvalidate = AssignRow(element, 0, mustInvalidate);
             }
             break;
         case PrimarySecondaryLayout.PrimaryTopSecondaryBottom:
             mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
             mustInvalidate = AssignRow(primary, 0, mustInvalidate);
             foreach (var element in secondary)
             {
                 mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                 mustInvalidate = AssignRow(element, 2, mustInvalidate);
             }
             break;
         case PrimarySecondaryLayout.SecondaryTopPrimaryBottom:
             mustInvalidate = AssignColumn(primary, 0, mustInvalidate);
             mustInvalidate = AssignRow(primary, 2, mustInvalidate);
             foreach (var element in secondary)
             {
                 mustInvalidate = AssignColumn(element, 0, mustInvalidate);
                 mustInvalidate = AssignRow(element, 0, mustInvalidate);
             }
             break;
     }
     return mustInvalidate;
 }