/// <summary>
        /// Measure the tab items for docking at the left or right
        /// </summary>
        private Size MeasureVertical(Size availableSize)
        {
            int    childCount            = InternalChildren.Count;
            double maxChildWidthOrHeight = 0d;

            EnsureChildRects();

            double extentHeight = 0d;

            double[] heights = new double[childCount];

            // we will first measure all the children with unlimited space to get their desired sizes
            // this will also get us the height required for all TabItems
            for (int i = 0; i < childCount; i++)
            {
                TabItem tabItem = InternalChildren[i] as TabItem;
                if (tabItem == null)
                {
                    return(new Size());
                }

                SetDimensions(tabItem);

                tabItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                ClearDimensions(tabItem);

                // calculate the maximum child width
                maxChildWidthOrHeight = Math.Max(maxChildWidthOrHeight, Math.Ceiling(tabItem.DesiredSize.Width));

                // calculate the child width while respecting the Maximum & Minimum width constraints
                heights[i] = Math.Min(MaximumChildHeight, Math.Max(MinimumChildHeight, Math.Ceiling(tabItem.DesiredSize.Height)));

                // determines how much horizontal space we require
                extentHeight += heights[i];
            }
            maxChildWidthOrHeight = Math.Max(MinimumChildWidth, Math.Min(MaximumChildWidth, maxChildWidthOrHeight));  // observe the constraints
            _extent = new Size(maxChildWidthOrHeight, extentHeight);

            bool flag = false;

            // 1). all the children fit into the available space using there desired widths
            if (extentHeight <= availableSize.Height)
            {
                _maxVisibleItems  = childCount;
                FirstVisibleIndex = 0;

                double top = 0;
                for (int i = 0; i < childCount; i++)
                {
                    _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                    top           += heights[i];

                    FrameworkElement child = InternalChildren[i] as FrameworkElement;
                    if (child != null)
                    {
                        child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                    }
                }

                CanScrollLeftOrUp    = false;
                CanScrollRightOrDown = false;

                flag = true;
            }

            // 2). all the children fit in the available space if we reduce their widths to a uniform value
            // while staying within the MinimumChildWidth and MaximumChildWidth constraints
            if (!flag)
            {
                // make sure the width is not greater than the MaximumChildWidth constraints
                double targetHeight = Math.Min(MaximumChildHeight, availableSize.Height / childCount);

                // target width applies now if whether we can fit all items in the available space or whether we are scrolling
                if (targetHeight >= MinimumChildHeight)
                {
                    _maxVisibleItems  = childCount;
                    FirstVisibleIndex = 0;

                    extentHeight = 0;
                    double top = 0;

                    for (int i = 0; i < childCount; i++)
                    {
                        extentHeight  += targetHeight;
                        heights[i]     = targetHeight;
                        _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                        top           += heights[i];

                        FrameworkElement child = InternalChildren[i] as FrameworkElement;
                        if (child != null)
                        {
                            child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                        }
                    }
                    _extent = new Size(maxChildWidthOrHeight, extentHeight);

                    flag = true;

                    CanScrollLeftOrUp    = false;
                    CanScrollRightOrDown = false;
                }
            }

            // 3) we can not fit all the children in the viewport, so now we will enable scrolling/virtualizing items
            if (!flag)
            {
                _maxVisibleItems = (int)Math.Floor(_viewPort.Height / MinimumChildHeight);          // calculate how many visible children we can show at once
                double targetHeight = availableSize.Height / _maxVisibleItems;                      // calculate the new target width
                FirstVisibleIndex = _firstVisibleIndex;

                extentHeight = 0;
                double top = 0;
                for (int i = 0; i < childCount; i++)
                {
                    extentHeight  += targetHeight;
                    heights[i]     = targetHeight;
                    _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                    top           += heights[i];

                    FrameworkElement child = InternalChildren[i] as FrameworkElement;
                    if (child != null)
                    {
                        child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                    }
                }
                _extent = new Size(maxChildWidthOrHeight, extentHeight);

                CanScrollLeftOrUp    = LastVisibleIndex < childCount - 1;
                CanScrollRightOrDown = FirstVisibleIndex > 0;
            }

            return(new Size(maxChildWidthOrHeight, double.IsInfinity(availableSize.Height) ? _extent.Height : availableSize.Height));
        }
        /// <summary>
        /// Measure the tab items for docking at the top or bottom
        /// </summary>
        private Size MeasureHorizontal(Size availableSize)
        {
            double maxChildWidthOrHeight = 0d;
            int    childCount            = InternalChildren.Count;

            EnsureChildRects();

            double extentWidth = 0d;

            double[] widths = new double[childCount];  // stores the widths of the items for use in the arrange pass

            for (int i = 0; i < childCount; i++)
            {
                TabItem tabItem = InternalChildren[i] as TabItem;
                if (tabItem == null)
                {
                    return(new Size());
                }

                SetDimensions(tabItem);

                tabItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                ClearDimensions(tabItem);

                // calculate the maximum child height
                maxChildWidthOrHeight = Math.Max(maxChildWidthOrHeight, Math.Ceiling(tabItem.DesiredSize.Height));

                // calculate the child width while respecting the Maximum & Minimum width constraints
                widths[i] = Math.Min(MaximumChildWidth, Math.Max(MinimumChildWidth, Math.Ceiling(tabItem.DesiredSize.Width)));

                // determines how much horizontal space we require
                extentWidth += widths[i];
            }
            maxChildWidthOrHeight = Math.Max(MinimumChildHeight, Math.Min(MaximumChildHeight, maxChildWidthOrHeight));  // observe the constraints
            _extent = new Size(extentWidth, maxChildWidthOrHeight);

            bool flag = false;

            // 1). all the children fit into the available space using there desired widths
            if (extentWidth <= availableSize.Width)
            {
                _maxVisibleItems  = childCount;
                FirstVisibleIndex = 0;

                double left = 0;
                for (int i = 0; i < childCount; i++)
                {
                    _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                    left          += widths[i];

                    FrameworkElement child = InternalChildren[i] as FrameworkElement;
                    if (child != null)
                    {
                        child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                    }
                }

                CanScrollLeftOrUp    = false;
                CanScrollRightOrDown = false;

                flag = true;
            }

            // 2). all the children fit in the available space if we reduce their widths to a uniform value
            // while staying within the MinimumChildWidth and MaximumChildWidth constraints
            if (!flag)
            {
                // make sure the width is not greater than the MaximumChildWidth constraints
                double targetWidth = Math.Min(MaximumChildWidth, availableSize.Width / childCount);

                // target width applies now if whether we can fit all items in the available space or whether we are scrolling
                if (targetWidth >= MinimumChildWidth)
                {
                    _maxVisibleItems  = childCount;
                    FirstVisibleIndex = 0;

                    extentWidth = 0;
                    double left = 0;

                    for (int i = 0; i < childCount; i++)
                    {
                        extentWidth   += targetWidth;
                        widths[i]      = targetWidth;
                        _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                        left          += widths[i];

                        FrameworkElement child = InternalChildren[i] as FrameworkElement;
                        if (child != null)
                        {
                            child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                        }
                    }
                    _extent = new Size(extentWidth, maxChildWidthOrHeight);

                    flag = true;

                    CanScrollLeftOrUp    = false;
                    CanScrollRightOrDown = false;
                }
            }

            // 3) we can not fit all the children in the viewport, so now we will enable scrolling/virtualizing items
            if (!flag)
            {
                _maxVisibleItems = (int)Math.Floor(_viewPort.Width / MinimumChildWidth);            // calculate how many visible children we can show at once
                if (_maxVisibleItems == 0)
                {
                    _maxVisibleItems = 1;
                }

                double targetWidth = availableSize.Width / _maxVisibleItems;                        // calculate the new target width
                FirstVisibleIndex = _firstVisibleIndex;

                extentWidth = 0;
                double left = 0;
                for (int i = 0; i < childCount; i++)
                {
                    extentWidth += targetWidth;
                    widths[i]    = targetWidth;

                    _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                    left          += widths[i];


                    FrameworkElement child = InternalChildren[i] as FrameworkElement;
                    if (child != null)
                    {
                        child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                    }
                }
                _extent = new Size(extentWidth, maxChildWidthOrHeight);

                CanScrollLeftOrUp    = LastVisibleIndex < childCount - 1;
                CanScrollRightOrDown = FirstVisibleIndex > 0;
            }

            return(new Size(double.IsInfinity(availableSize.Width) ? _extent.Width : availableSize.Width, maxChildWidthOrHeight));
        }