Beispiel #1
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var realizationRect    = context.RealizationRect;
            int itemCount          = context.ItemCount;
            int firstRealizedIndex = FirstRealizedIndexInRect(realizationRect, itemCount);
            int lastRealizedIndex  = LastRealizedIndexInRect(realizationRect, itemCount);

            Debug.WriteLine("Measure:" + realizationRect.ToString());

            // Viewport + Buffer Rect.
            for (int currentIndex = firstRealizedIndex; currentIndex <= lastRealizedIndex; currentIndex++)
            {
                var element = context.GetOrCreateElementAt(currentIndex);
                element.Measure(new Size(ItemWidth, ItemHeight));
            }

            // Anchor
            var anchorIndex = context.RecommendedAnchorIndex;

            if (anchorIndex >= 0)
            {
                var anchorElement = context.GetOrCreateElementAt(anchorIndex);
                anchorElement.Measure(new Size(ItemWidth, ItemHeight));
            }

            return(new Size(ItemWidth, context.ItemCount * ItemHeight));
        }
Beispiel #2
0
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            var realizationRect    = context.RealizationRect;
            int itemCount          = context.ItemCount;
            int firstRealizedIndex = FirstRealizedIndexInRect(realizationRect, itemCount);
            int lastRealizedIndex  = LastRealizedIndexInRect(realizationRect, itemCount);

            Debug.WriteLine("Arrange:" + realizationRect.ToString());

            // Viewport + Buffer Rect.
            for (int currentIndex = firstRealizedIndex; currentIndex <= lastRealizedIndex; currentIndex++)
            {
                var element     = context.GetOrCreateElementAt(currentIndex);
                var arrangeRect = new Rect(0, currentIndex * ItemHeight, ItemWidth, ItemHeight);
                element.Arrange(arrangeRect);
                Debug.WriteLine("   Arrange:" + currentIndex + " :" + arrangeRect);
            }

            // Anchor
            var anchorIndex = context.RecommendedAnchorIndex;

            if (anchorIndex >= 0)
            {
                var anchor      = context.GetOrCreateElementAt(anchorIndex);
                var arrangeRect = new Rect(0, anchorIndex * ItemHeight, ItemWidth, ItemHeight);
                anchor.Arrange(arrangeRect);
                Debug.WriteLine("   Arrange:" + anchorIndex + " :" + arrangeRect);
            }

            return(finalSize);
        }
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var viewport = context.RealizationRect;

            if (availableSize.Width != m_lastAvailableWidth || cachedBoundsInvalid)
            {
                UpdateCachedBounds(availableSize);
                m_lastAvailableWidth = availableSize.Width;
            }

            // Initialize column offsets
            int numColumns = (int)(availableSize.Width / Width);

            if (m_columnOffsets.Count == 0)
            {
                for (int i = 0; i < numColumns; i++)
                {
                    m_columnOffsets.Add(0);
                }
            }

            m_firstIndex = GetStartIndex(viewport);
            int    currentIndex = m_firstIndex;
            double nextOffset   = -1.0;

            // Measure items from start index to when we hit the end of the viewport.
            while (currentIndex < context.ItemCount && nextOffset < viewport.Bottom)
            {
                var child = context.GetOrCreateElementAt(currentIndex);
                child.Measure(new Size(Width, availableSize.Height));

                if (currentIndex >= m_cachedBounds.Count)
                {
                    // We do not have bounds for this index. Lay it out and cache it.
                    int columnIndex = GetIndexOfLowestColumn(m_columnOffsets, out nextOffset);
                    m_cachedBounds.Add(new Rect(columnIndex * Width, nextOffset, Width, child.DesiredSize.Height));
                    m_columnOffsets[columnIndex] += child.DesiredSize.Height;
                }
                else
                {
                    if (currentIndex + 1 == m_cachedBounds.Count)
                    {
                        // Last element. Use the next offset.
                        GetIndexOfLowestColumn(m_columnOffsets, out nextOffset);
                    }
                    else
                    {
                        nextOffset = m_cachedBounds[currentIndex + 1].Top;
                    }
                }

                m_lastIndex = currentIndex;
                currentIndex++;
            }

            var extent = GetExtentSize(availableSize);

            return(extent);
        }
Beispiel #4
0
 protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
 {
     if (this.m_cachedBounds.Count > 0)
     {
         for (int index = this.m_firstIndex; index <= this.m_lastIndex; index++)
         {
             var child = context.GetOrCreateElementAt(index);
             child.Arrange(this.m_cachedBounds[index]);
         }
     }
     return(finalSize);
 }
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var itemCount = context.ItemCount;

            for (int i = 0; i < context.ItemCount; i++)
            {
                var container = context.GetOrCreateElementAt(i);
                container.Measure(new Size(ItemSize, ItemSize));
            }

            return(availableSize);
        }
Beispiel #6
0
        private void UnifyRowWidth(VirtualizingLayoutContext context, Size availableSize, double unifedRowWidthLimit)
        {
            if (this._rowCachedBounds.Count > 0)
            {
                double previousWidthDiff = 0;

                var biggestXOffSet = this._rowXOffSet.Max();

                for (int row = 0; row < this._rowCachedBounds.Count; row++)
                {
                    var rowItems              = this._rowCachedBounds[row];
                    var currentXOffSet        = 0d;
                    var nextRowIndex          = row + 1;
                    var xOffsettDif           = 0d;
                    var currentMaxChildHeight = rowItems.Count > 0 ? rowItems.Max(x => x.Height) : this._rowHeight[row];
                    var rowBaseHeight         = this._rowHeight[row];

                    if (this._rowXOffSet[row] < biggestXOffSet)
                    {
                        var diff = biggestXOffSet - this._rowXOffSet[row];

                        xOffsettDif = diff / rowItems.Count;
                    }

                    // Childs werden neu berechnet Höhe , Breite
                    for (int index = 0; index < rowItems.Count; index++)
                    {
                        var oldRectangle = rowItems[index];
                        var childWidth   = oldRectangle.Width;

                        var currentDesiredWidth = childWidth + xOffsettDif;

                        var childIndex = this.FindIndexOfRowChild(row, index);
                        var child      = context.GetOrCreateElementAt(childIndex);
                        child.Measure(new Size(currentDesiredWidth, availableSize.Height));

                        var childMaxWidth = (double)child.GetValue(FrameworkElement.MaxWidthProperty);
                        if (currentDesiredWidth <= childMaxWidth)
                        {
                            oldRectangle.Width = currentDesiredWidth;

                            oldRectangle.X  = currentXOffSet;
                            rowItems[index] = oldRectangle;
                        }

                        currentXOffSet += currentDesiredWidth + this.ColumnSpacing;
                    }

                    this._rowXOffSet[row] = currentXOffSet;
                }
            }
        }
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            var itemCount      = context.ItemCount;
            var radius         = GetCircleRadius(finalSize) - ItemSize / 2.0;
            var angleIncrement = 2 * Math.PI / itemCount;
            var angle          = 0.0;

            for (int i = 0; i < context.ItemCount; i++)
            {
                var container = context.GetOrCreateElementAt(i);
                var x         = Math.Sin(angle) * radius - ItemSize / 2.0 + finalSize.Width / 2.0;
                var y         = -Math.Cos(angle) * radius - ItemSize / 2.0 + finalSize.Height / 2.0;
                container.Arrange(new Rect(x, y, ItemSize, ItemSize));
                angle += angleIncrement;
            }

            return(finalSize);
        }
Beispiel #8
0
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            DebugTrace("ArrangeOverride: Viewport" + context.RealizationRect);
            for (int realizationIndex = 0; realizationIndex < m_realizedElementBounds.Count; realizationIndex++)
            {
                int currentDataIndex = m_firstRealizedDataIndex + realizationIndex;
                DebugTrace("Arranging " + currentDataIndex);

                // Arrange the child. If any alignment needs to be done, it
                // can be done here.
                var child         = context.GetOrCreateElementAt(currentDataIndex);
                var arrangeBounds = m_realizedElementBounds[realizationIndex];
                arrangeBounds.X -= m_lastExtent.X;
                arrangeBounds.Y -= m_lastExtent.Y;
                child.Arrange(arrangeBounds);
            }

            return(finalSize);
        }
Beispiel #9
0
        private Size MeasureElement(VirtualizingLayoutContext context, int index, Size availableSize)
        {
            var child = context.GetOrCreateElementAt(index);

            child.Measure(availableSize);

            int  estimationBufferIndex = index % m_estimationBuffer.Count;
            bool alreadyMeasured       = m_estimationBuffer[estimationBufferIndex] != 0;

            if (!alreadyMeasured)
            {
                m_numItemsUsedForEstimation++;
            }

            m_totalHeightForEstimation -= m_estimationBuffer[estimationBufferIndex];
            m_totalHeightForEstimation += child.DesiredSize.Height;
            m_estimationBuffer[estimationBufferIndex] = child.DesiredSize.Height;

            return(child.DesiredSize);
        }
Beispiel #10
0
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            if (this._rowCachedBounds.Count > 0)
            {
                for (int row = this.m_firstIndex; row <= this._rowCachedBounds.Count - 1; row++)
                {
                    var rowItems = this._rowCachedBounds[row];

                    for (int index = 0; index < rowItems.Count; index++)
                    {
                        var childIndex = this.FindIndexOfRowChild(row, index);
                        var child      = context.GetOrCreateElementAt(childIndex);

                        var rect = rowItems[index];
                        child.Arrange(rect);
                    }
                }
            }
            return(finalSize);
        }
Beispiel #11
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            if (this.MinItemSize == Size.Empty)
            {
                var firstElement = context.GetOrCreateElementAt(0);
                firstElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                // setting the member value directly to skip invalidating layout
                this._minItemSize = firstElement.DesiredSize;
            }

            // Determine which rows need to be realized.  We know every row will have the same height and
            // only contain 3 items.  Use that to determine the index for the first and last item that
            // will be within that realization rect.
            var firstRowIndex = Math.Max(
                (int)(context.RealizationRect.Y / (this.MinItemSize.Height + this.RowSpacing)) - 1,
                0);
            var lastRowIndex = Math.Min(
                (int)(context.RealizationRect.Bottom / (this.MinItemSize.Height + this.RowSpacing)) + 1,
                (int)(context.ItemCount / 3));

            // Determine which items will appear on those rows and what the rect will be for each item
            var state = context.LayoutState as ActivityFeedLayoutState;

            state.LayoutRects.Clear();

            // Save the index of the first realized item.  We'll use it as a starting point during arrange.
            state.FirstRealizedIndex = firstRowIndex * 3;

            // ideal item width that will expand/shrink to fill available space
            double desiredItemWidth = Math.Max(this.MinItemSize.Width, (availableSize.Width - this.ColumnSpacing * 3) / 4);

            // Foreach item between the first and last index,
            //     Call GetElementOrCreateElementAt which causes an element to either be realized or retrieved
            //       from a recycle pool
            //     Measure the element using an appropriate size
            //
            // Any element that was previously realized which we don't retrieve in this pass (via a call to
            // GetElementOrCreateAt) will be automatically cleared and set aside for later re-use.
            // Note: While this work fine, it does mean that more elements than are required may be
            // created because it isn't until after our MeasureOverride completes that the unused elements
            // will be recycled and available to use.  We could avoid this by choosing to track the first/last
            // index from the previous layout pass.  The diff between the previous range and current range
            // would represent the elements that we can pre-emptively make available for re-use by calling
            // context.RecycleElement(element).
            for (int rowIndex = firstRowIndex; rowIndex < lastRowIndex; rowIndex++)
            {
                int firstItemIndex      = rowIndex * 3;
                var boundsForCurrentRow = CalculateLayoutBoundsForRow(rowIndex, desiredItemWidth);

                for (int columnIndex = 0; columnIndex < 3; columnIndex++)
                {
                    var index     = firstItemIndex + columnIndex;
                    var rect      = boundsForCurrentRow[index % 3];
                    var container = context.GetOrCreateElementAt(index);

                    container.Measure(
                        new Size(boundsForCurrentRow[columnIndex].Width, boundsForCurrentRow[columnIndex].Height));

                    state.LayoutRects.Add(boundsForCurrentRow[columnIndex]);
                }
            }

            // Calculate and return the size of all the content (realized or not) by figuring out
            // what the bottom/right position of the last item would be.
            var extentHeight = ((int)(context.ItemCount / 3) - 1) * (this.MinItemSize.Height + this.RowSpacing) + this.MinItemSize.Height;

            // Report this as the desired size for the layout
            return(new Size(desiredItemWidth * 4 + this.ColumnSpacing * 2, extentHeight));
        }
Beispiel #12
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var viewport = context.RealizationRect;

            Debug.WriteLine($"availableSize X,Y:{availableSize.Width}, {availableSize.Height}");

            if (availableSize.Width != this.m_lastAvailableWidth || this.cachedBoundsInvalid)
            {
                this.UpdateCachedBounds(availableSize);
                this.m_lastAvailableWidth = availableSize.Width;
            }

            // 列オフセットの初期化
            int numColumns = (int)(availableSize.Width / 150);

            Debug.WriteLine($"列数-150:{numColumns}");



            if (this.m_columnOffsets.Count == 0)
            {
                for (int i = 0; i < numColumns; i++)
                {
                    this.m_columnOffsets.Add(0);
                }
            }

            if (numColumns % 2 == 0)
            {
                this.Width = 150;
                Debug.WriteLine($"this.Width-0:{this.Width}");
            }
            else
            {
                if (numColumns < 2)
                {
                }
                else
                {
                    this.Width = 230;
                    numColumns = (int)(availableSize.Width / 201);
                    Debug.WriteLine($"this.Width-1:{this.Width}");
                    //                    this.Width = (int)(availableSize.Width / (numColumns - 1));
                    // numColumns = numColumns - 1;
                }
                //              return this.GetExtentSize(availableSize);
            }


            Debug.WriteLine($"列数:{numColumns}");

            this.m_firstIndex = this.GetStartIndex(viewport);
            int    currentIndex = this.m_firstIndex;
            double nextOffset   = -1.0;

            // 開始インデックスからビューポートの終わりまでの項目を計測します。
            while (currentIndex < context.ItemCount && nextOffset < viewport.Bottom)
            {
                var child = context.GetOrCreateElementAt(currentIndex);
                child.Measure(new Size(this.Width, availableSize.Height));

                if (currentIndex >= this.m_cachedBounds.Count)
                {
                    // このインデックスには境界線がありません。レイアウトしてキャッシュします。
                    int columnIndex = this.GetIndexOfLowestColumn(this.m_columnOffsets, out nextOffset);
                    this.m_cachedBounds.Add(new Rect(columnIndex * this.Width, nextOffset, this.Width, child.DesiredSize.Height));
                    this.m_columnOffsets[columnIndex] += child.DesiredSize.Height;
                }
                else
                {
                    if (currentIndex + 1 == this.m_cachedBounds.Count)
                    {
                        // Last element. Use the next offset.
                        this.GetIndexOfLowestColumn(this.m_columnOffsets, out nextOffset);
                    }
                    else
                    {
                        nextOffset = this.m_cachedBounds[currentIndex + 1].Top;
                    }
                }

                this.m_lastIndex = currentIndex;
                currentIndex++;
            }



            var extent = this.GetExtentSize(availableSize);

            Debug.WriteLine($"extent,Y:{extent.Width}, {extent.Height}");

            return(extent);
        }
Beispiel #13
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            if (this.MinItemSize == Size.Empty)
            {
                var firstElement = context.GetOrCreateElementAt(0);
                firstElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                // メンバー値を直接設定してレイアウトの無効化をスキップする
                this._minItemSize = firstElement.DesiredSize;
            }

            System.Diagnostics.Debug.WriteLine($"{context.RealizationRect.X},{context.RealizationRect.Y},|| {this.MinItemSize.Height},{this.MinItemSize.Width} ");

            // どの行を実現する必要があるかを決定します。 どの行も同じ高さで、3つの項目しか含まれていないことがわかっています。
            // これを使って、実現される矩形内の最初の項目と最後の項目のインデックスを決定します。
            var firstRowIndex = Math.Max(
                (int)(context.RealizationRect.Y / (this.MinItemSize.Height + this.RowSpacing)) - 1,
                0);
            var lastRowIndex = Math.Min(
                (int)(context.RealizationRect.Bottom / (this.MinItemSize.Height + this.RowSpacing)) + 1,
                (int)(context.ItemCount / 3));

            // これらの行に表示されるアイテムを特定し、各アイテムのための長方形を決定します。
            var state = context.LayoutState as ActivityFeedLayoutState;

            state.LayoutRects.Clear();

            // 最初に表示されたアイテムのインデックスを保存します。 アレンジ時の起点として使用します。
            state.FirstRealizedIndex = firstRowIndex * 2;

            // 空いているスペースを埋めるために伸縮する理想的なアイテム幅
            double desiredItemWidth = Math.Max(this.MinItemSize.Width, (availableSize.Width - this.ColumnSpacing * 1) / 2);

            // Foreach item between the first and last index,
            //     Call GetElementOrCreateElementAt which causes an element to either be realized or retrieved
            //       from a recycle pool
            //     Measure the element using an appropriate size
            //
            // Any element that was previously realized which we don't retrieve in this pass (via a call to
            // GetElementOrCreateAt) will be automatically cleared and set aside for later re-use.
            // Note: While this work fine, it does mean that more elements than are required may be
            // created because it isn't until after our MeasureOverride completes that the unused elements
            // will be recycled and available to use.  We could avoid this by choosing to track the first/last
            // index from the previous layout pass.  The diff between the previous range and current range
            // would represent the elements that we can preemptively make available for re-use by calling
            // context.RecycleElement(element).
            //最初のインデックスと最後のインデックスの間の項目を検索します。
            //GetElementOrCreateElementAt を呼び出すと、要素が実現されるか、リサイクルプールから取得されます。
            //適切なサイズを使用して要素を測定します。

            //以前に実現された要素で、このパスで(GetElementOrCreateAt の呼び出しを介して)取得しなかったものは、自動的にクリアされ、後で再利用するために脇に置かれます。
            //注意してください。
            //これは正常に動作しますが、必要以上に多くの要素が作成される可能性があることを意味します。
            //これは、前回のレイアウトパスの最初 / 最後のインデックスを追跡することを選択することで回避できます。
            //前の範囲と現在の範囲の差分は、context.RecycleElement(element) を呼び出すことで再利用可能にすることができる要素を表します。

            for (int rowIndex = firstRowIndex; rowIndex < lastRowIndex; rowIndex++)
            {
                int firstItemIndex      = rowIndex * 2;
                var boundsForCurrentRow = this.CalculateLayoutBoundsForRow(rowIndex, desiredItemWidth);

                for (int columnIndex = 0; columnIndex < 2; columnIndex++)
                {
                    var index     = firstItemIndex + columnIndex;
                    var rect      = boundsForCurrentRow[index % 2];
                    var container = context.GetOrCreateElementAt(index);

                    container.Measure(
                        new Size(boundsForCurrentRow[columnIndex].Width, boundsForCurrentRow[columnIndex].Height));

                    state.LayoutRects.Add(boundsForCurrentRow[columnIndex]);
                }
            }

            // 最後の項目の下/右の位置がどうなるかを計算して、すべてのコンテンツ(表示されていてもいなくても)のサイズを計算して返す。
            var extentHeight = ((int)(context.ItemCount / 3) - 1) * (this.MinItemSize.Height + this.RowSpacing) + this.MinItemSize.Height;

            System.Diagnostics.Debug.WriteLine($"{desiredItemWidth},{extentHeight} ");


            // これをレイアウトのサイズとして報告する
            return(new Size(desiredItemWidth * 2 + this.ColumnSpacing * 1, extentHeight));
        }
Beispiel #14
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var realWidth = 0d;

            if (this.Width == 0 || this.Width > availableSize.Width)
            {
                realWidth = availableSize.Width;
            }
            else
            {
                realWidth = this.Width;
            }


            var viewport = context.RealizationRect;


            // Update Logic when Items are still here
            if (availableSize.Width != this.m_lastAvailableWidth || this.cachedBoundsInvalid)
            {
                this.UpdateCachedBounds(context, availableSize, realWidth);
                this.m_lastAvailableWidth = availableSize.Width;

                if (this.UnifedRowWidthLimit != 0 && this.UnifedRowWidthLimit > this.m_lastAvailableWidth)
                {
                    this.UnifyRowWidth(context, availableSize, this.UnifedRowWidthLimit);
                }
            }



            this.m_firstIndex = this.GetStartIndex(viewport);
            int    currentIndex           = this.m_firstIndex;
            int    currentRowIndex        = 0;
            double nextYOffset            = -1.0;
            double nextXOffset            = -1.0;
            double diff                   = 0d;
            var    currentCachedItemCount = this._rowCachedBounds.Values.Count;

            if (this.cachedBoundsInvalid)
            {
                // Measure items from start index to when we hit the end of the viewport.
                while (currentIndex < context.ItemCount && nextYOffset < viewport.Bottom)
                {
                    var child = context.GetOrCreateElementAt(currentIndex);

                    child.Measure(new Size(realWidth, availableSize.Height));

                    if (currentIndex >= currentCachedItemCount)
                    {
                        // We do not have bounds for this index. Lay it out and cache it.
                        currentRowIndex = this.GetIndexOfLowestRow(child, realWidth, out nextXOffset);
                        nextYOffset     = currentRowIndex == 0 ? 0 : this._rowHeight[currentRowIndex];
                        //  int columnIndex = GetIndexOfLowestColumn(m_columnOffsets, child, realWidth, out nextYOffset);
                        var currentBound = new Rect(nextXOffset, nextYOffset, child.DesiredSize.Width, child.DesiredSize.Height);

                        if (this._rowCachedBounds.ContainsKey(currentRowIndex))
                        {
                            this._rowCachedBounds[currentRowIndex].Add(currentBound);
                        }

                        this.UpdateRowHeight(child.DesiredSize.Height, currentRowIndex);

                        this._rowXOffSet[currentRowIndex] += child.DesiredSize.Width + this.ColumnSpacing;
                    }

                    this.m_lastIndex = currentRowIndex;
                    currentIndex++;
                }

                if (this.UnifedRowWidthLimit != 0 && this.UnifedRowWidthLimit > this.m_lastAvailableWidth)
                {
                    this.UnifyRowWidth(context, availableSize, this.UnifedRowWidthLimit);
                }

                this.cachedBoundsInvalid = false;
            }


            var extent = this.GetExtentSize(availableSize);

            return(extent);
        }
Beispiel #15
0
        private void UpdateCachedBounds(VirtualizingLayoutContext context, Size availableSize, double realWidth)
        {
            int numColumns = (int)(availableSize.Width / realWidth);

            numColumns = numColumns == 0 ? 1 : numColumns;
            this.m_columnOffsets.Clear();

            for (int i = 0; i < numColumns; i++)
            {
                this.m_columnOffsets.Add(0);
            }

            if (this._rowCachedBounds.Count > 0)
            {
                double previousWidthDiff = 0;

                for (int row = 0; row < this._rowCachedBounds.Count; row++)
                {
                    var rowItems              = this._rowCachedBounds[row];
                    var currentXOffSet        = 0d;
                    var nextRowIndex          = row + 1;
                    var currentMaxChildHeight = rowItems.Count > 0 ? rowItems.Max(x => x.Height) : this._rowHeight[row];
                    var rowBaseHeight         = this._rowHeight[row];


                    // Childs werden neu berechnet Höhe , Breite
                    for (int index = 0; index < rowItems.Count; index++)
                    {
                        var childIndex = this.FindIndexOfRowChild(row, index);
                        var child      = context.GetOrCreateElementAt(childIndex);
                        child.Measure(new Size(realWidth, availableSize.Height));

                        var oldRectangle = rowItems[index];

                        var currentChildHeight = rowBaseHeight + child.DesiredSize.Height + this.RowSpacing;

                        if (nextRowIndex < this._rowHeight.Count && (this._rowHeight[nextRowIndex] < currentChildHeight))
                        {
                            var heightDiff = currentChildHeight - this._rowHeight[nextRowIndex];

                            for (int nextRows = nextRowIndex; nextRows < this._rowHeight.Count; nextRows++)
                            {
                                this._rowHeight[nextRows] += heightDiff;
                            }
                        }

                        if (nextRowIndex < this._rowHeight.Count && (this._rowHeight[nextRowIndex] > currentChildHeight) && currentMaxChildHeight == oldRectangle.Height)
                        {
                            var heightDiff = currentChildHeight - this._rowHeight[nextRowIndex];

                            for (int nextRows = nextRowIndex; nextRows < this._rowHeight.Count; nextRows++)
                            {
                                this._rowHeight[nextRows] += heightDiff;
                            }
                        }

                        oldRectangle.X      = currentXOffSet;
                        oldRectangle.Width  = child.DesiredSize.Width;
                        oldRectangle.Height = child.DesiredSize.Height;
                        oldRectangle.Y      = row == 0 ? 0d : this._rowHeight[row];
                        rowItems[index]     = oldRectangle;
                        currentXOffSet     += child.DesiredSize.Width + this.ColumnSpacing;
                    }

                    this._rowXOffSet[row] = currentXOffSet;

                    // Letztes Item in die nächste Zeile
                    if (this._rowXOffSet[row] > availableSize.Width && rowItems.Count > 1)
                    {
                        var lastChildIndex           = rowItems.Count - 1;
                        var lastChildCurrentRowIndex = this.FindIndexOfRowChild(row, lastChildIndex);

                        var lastChild = context.GetOrCreateElementAt(lastChildCurrentRowIndex);

                        var rowHeight = 0d;

                        if (nextRowIndex < this._rowHeight.Count - 1)
                        {
                            rowHeight = this._rowHeight[nextRowIndex];
                        }
                        else
                        {
                            this.AddNewRow(lastChild);
                        }

                        var newBound = new Rect(0d, rowHeight, lastChild.DesiredSize.Width, lastChild.DesiredSize.Height);

                        if (this._rowCachedBounds.ContainsKey(nextRowIndex))
                        {
                            this._rowCachedBounds[nextRowIndex].Insert(0, newBound);
                        }

                        this.UpdateRowHeight(lastChild.DesiredSize.Height, nextRowIndex);
                        this._rowXOffSet[row] -= lastChild.DesiredSize.Width + this.ColumnSpacing;
                        rowItems.RemoveAt(lastChildIndex);
                    }


                    // Hinzufügen zur aktuellen Zeile
                    else
                    {
                        if (this._rowCachedBounds.TryGetValue(nextRowIndex, out var childs) && childs.Count > 0)
                        {
                            var nextRowChildIndex = this.FindIndexOfRowChild(nextRowIndex, 0);
                            var nextRowChild      = context.GetOrCreateElementAt(nextRowChildIndex);

                            if (this.FirstChildFromNextRowFitsIntoCurrentRow(nextRowChild, realWidth, row))
                            {
                                var child = childs[0];

                                var rowHeigt = row == 0 ? 0 : this._rowHeight[row];
                                var newBound = new Rect(this._rowXOffSet[row], rowHeigt, nextRowChild.DesiredSize.Width, nextRowChild.DesiredSize.Height);
                                rowItems.Add(newBound);
                                this._rowXOffSet[row] += nextRowChild.DesiredSize.Width + this.ColumnSpacing;

                                this._rowXOffSet[nextRowIndex] -= nextRowChild.DesiredSize.Width + this.ColumnSpacing;

                                if (childs.Count - 1 != 0)
                                {
                                    var maxHeight = childs.Max(x => x.Height);

                                    if (maxHeight <= nextRowChild.DesiredSize.Height)
                                    {
                                        var childsWithoutNextRowChild = new List <Rect>(childs);

                                        childsWithoutNextRowChild.RemoveAt(0);

                                        maxHeight = childsWithoutNextRowChild.Max(x => x.Height);

                                        var diff = nextRowChild.DesiredSize.Height - maxHeight;

                                        for (int i = nextRowIndex; i < this._rowHeight.Count; i++)
                                        {
                                            this._rowHeight[i] -= diff;
                                        }
                                    }

                                    this.UpdateRowHeight(nextRowChild.DesiredSize.Height, row);
                                }

                                childs.RemoveAt(0);

                                if (nextRowIndex >= this._rowCachedBounds.Count - 1)
                                {
                                    this.DeleteRow(nextRowIndex);
                                }
                            }
                        }
                    }
                }
                this.cachedBoundsInvalid = false;
            }
        }