예제 #1
0
        // Figure out the extent of the layout by getting the number of items remaining
        // above and below the realized elements and getting an estimation based on
        // average item heights seen so far.
        private Rect EstimateExtent(VirtualizingLayoutContext context, Size availableSize)
        {
            double averageHeight = m_totalHeightForEstimation / m_numItemsUsedForEstimation;

            Rect extent = new Rect(0, 0, availableSize.Width, context.ItemCount * averageHeight);

            if (context.ItemCount > 0 && m_realizedElementBounds.Count > 0)
            {
                extent.Y = m_firstRealizedDataIndex == 0 ?
                           m_realizedElementBounds[0].Y :
                           m_realizedElementBounds[0].Y - (m_firstRealizedDataIndex - 1) * averageHeight;

                int lastRealizedIndex = m_firstRealizedDataIndex + m_realizedElementBounds.Count;
                if (lastRealizedIndex == context.ItemCount - 1)
                {
                    var lastBounds = m_realizedElementBounds[m_realizedElementBounds.Count - 1];
                    extent.Y = lastBounds.Bottom;
                }
                else
                {
                    var lastBounds                     = m_realizedElementBounds[m_realizedElementBounds.Count - 1];
                    int lastRealizedDataIndex          = m_firstRealizedDataIndex + m_realizedElementBounds.Count;
                    int numItemsAfterLastRealizedIndex = context.ItemCount - lastRealizedDataIndex;
                    extent.Height = lastBounds.Bottom + numItemsAfterLastRealizedIndex * averageHeight - extent.Y;
                }
            }

            DebugTrace("Extent " + extent + " with average height " + averageHeight);
            return(extent);
        }
예제 #2
0
        protected override Rect GetExtent(
            Size availableSize,
            VirtualizingLayoutContext context,
            UIElement firstRealized,
            int firstRealizedItemIndex,
            Rect firstRealizedLayoutBounds,
            UIElement lastRealized,
            int lastRealizedItemIndex,
            Rect lastRealizedLayoutBounds)
        {
            var extent = base.GetExtent(
                availableSize,
                context,
                firstRealized,
                firstRealizedItemIndex,
                firstRealizedLayoutBounds,
                lastRealized,
                lastRealizedItemIndex,
                lastRealizedLayoutBounds);

            return(GetExtentFunc != null?GetExtentFunc(
                       availableSize,
                       context,
                       firstRealized,
                       firstRealizedItemIndex,
                       firstRealizedLayoutBounds,
                       lastRealized,
                       lastRealizedItemIndex,
                       lastRealizedLayoutBounds,
                       extent) : extent);
        }
예제 #3
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));
        }
예제 #4
0
        protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
        {
            base.UninitializeForContextCore(context);

            // clear any state
            context.LayoutState = null;
        }
예제 #5
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);
        }
예제 #6
0
        // The data collection has changed, since we are maintaining the bounds of elements
        // in the viewport, we will update the list to account for the collection change.
        protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
        {
            InvalidateMeasure();
            if (m_realizedElementBounds.Count > 0)
            {
                switch (args.Action)
                {
                case NotifyCollectionChangedAction.Add:
                    OnItemsAdded(args.NewStartingIndex, args.NewItems.Count);
                    break;

                case NotifyCollectionChangedAction.Replace:
                    OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count);
                    OnItemsAdded(args.NewStartingIndex, args.NewItems.Count);
                    break;

                case NotifyCollectionChangedAction.Remove:
                    OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count);
                    break;

                case NotifyCollectionChangedAction.Reset:
                    m_realizedElementBounds.Clear();
                    m_firstRealizedDataIndex = 0;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }
        }
        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);
        }
예제 #8
0
 protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
 {
     base.UninitializeForContextCore(context);
     if (OnDetatchedFunc != null)
     {
         OnDetatchedFunc(context);
     }
 }
예제 #9
0
 protected override void InitializeForContextCore(VirtualizingLayoutContext context)
 {
     base.InitializeForContextCore(context);
     if (OnAttachedFunc != null)
     {
         OnAttachedFunc(context);
     }
 }
 protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
 {
     // The data collection has changed, so the bounds of all the indices are not valid anymore.
     // We need to re-evaluate all the bounds and cache them during the next measure.
     m_cachedBounds.Clear();
     m_firstIndex        = m_lastIndex = 0;
     cachedBoundsInvalid = true;
     InvalidateMeasure();
 }
예제 #11
0
 protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
 {
     // データ収集が変更されたため、すべてのインデックスの境界が無効になりました。
     // すべての境界を再評価し、次のメジャーでキャッシュする必要があります。.
     this.m_cachedBounds.Clear();
     this.m_firstIndex        = this.m_lastIndex = 0;
     this.cachedBoundsInvalid = false;
     this.InvalidateMeasure();
 }
예제 #12
0
        // Figure out which index to use as the anchor and start laying out around.
        private int GetStartIndex(VirtualizingLayoutContext context, Size availableSize)
        {
            int  startDataIndex = -1;
            var  anchorIndex    = context.RecommendedAnchorIndex;
            bool isAnchorValid  = anchorIndex != -1;

            if (isAnchorValid)
            {
                if (IsRealized(anchorIndex))
                {
                    startDataIndex = anchorIndex;
                }
                else
                {
                    ClearRealizedRange();
                    startDataIndex = anchorIndex;
                }
            }
            else
            {
                // find first realized element that is visible in the viewport.
                startDataIndex = GetFirstRealizedDataIndexInViewport(context.RealizationRect);
                if (startDataIndex < 0)
                {
                    startDataIndex = EstimateIndexForViewport(context.RealizationRect, context.ItemCount);
                    ClearRealizedRange();
                }
            }

            // We have an anchorIndex, realize and measure it and
            // figure out its bounds.
            if (startDataIndex != -1 & context.ItemCount > 0)
            {
                if (m_realizedElementBounds.Count == 0)
                {
                    m_firstRealizedDataIndex = startDataIndex;
                }

                var newAnchor = EnsureRealized(startDataIndex);
                DebugTrace("Measuring start index " + startDataIndex);
                var desiredSize = MeasureElement(context, startDataIndex, availableSize);

                var bounds = new Rect(
                    0,
                    newAnchor ?
                    (m_totalHeightForEstimation / m_numItemsUsedForEstimation) * startDataIndex :
                    GetCachedBoundsForDataIndex(startDataIndex).Y,
                    availableSize.Width,
                    desiredSize.Height);
                SetCachedBoundsForDataIndex(startDataIndex, bounds);
            }

            return(startDataIndex);
        }
예제 #13
0
        protected override void InitializeForContextCore(VirtualizingLayoutContext context)
        {
            base.InitializeForContextCore(context);

            if (!(context.LayoutState is ActivityFeedLayoutState state))
            {
                // 理論的には)レイアウトは複数の要素で同時に使用される可能性があるので、必要な状態を保存します。
                // 実際には、Xbox Activity Feed の場合は、おそらく単一のインスタンスしかありません。
                context.LayoutState = new ActivityFeedLayoutState();
            }
        }
예제 #14
0
        protected override void InitializeForContextCore(VirtualizingLayoutContext context)
        {
            base.InitializeForContextCore(context);

            if (!(context.LayoutState is ActivityFeedLayoutState state))
            {
                // Store any state we might need since (in theory) the layout could be in use by multiple
                // elements simultaneously
                // In reality for the Xbox Activity Feed there's probably only a single instance.
                context.LayoutState = new ActivityFeedLayoutState();
            }
        }
예제 #15
0
        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);
        }
예제 #16
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);
 }
예제 #17
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;
                }
            }
        }
예제 #18
0
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            // walk through the cache of containers and arrange
            var state          = context.LayoutState as ActivityFeedLayoutState;
            var virtualContext = context as VirtualizingLayoutContext;
            int currentIndex   = state.FirstRealizedIndex;

            foreach (var arrangeRect in state.LayoutRects)
            {
                var container = virtualContext.GetOrCreateElementAt(currentIndex);
                container.Arrange(arrangeRect);
                currentIndex++;
            }

            return(finalSize);
        }
예제 #19
0
        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);
        }
예제 #20
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);
        }
예제 #21
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);
        }
예제 #22
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);
        }
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            // In the Xbox scenario there isn't a user grabbing the window and resizing it.  Otherwise, it
            // might be useful to skip a full layout here and return a cached size until some condition is met
            // such as having enough room to fit another column.  That would require extra work like
            // tracking some additional state, comparing the virtualizing rect with the cached value.
            var virtualizingContext = context as VirtualizingLayoutContext;
            var realizationRect     = virtualizingContext.RealizationRect;

            // Determine which rows need to be realized
            var firstRowIndex = Math.Max((int)(realizationRect.Y / (this.MinItemSize.Height + this.RowSpacing)) - 1, 0);
            var lastRowIndex  = Math.Min((int)(realizationRect.Bottom / (this.MinItemSize.Height + this.RowSpacing)) + 1, (int)(context.ItemCount / 3));

            // Determine which items fall on those rows and determine the rect for each item
            var state = context.LayoutState as ActivityFeedLayoutState;

            state.LayoutRects.Clear();
            state.FirstRealizedIndex = firstRowIndex * 3;

            for (int rowIndex = firstRowIndex; rowIndex < lastRowIndex; rowIndex++)
            {
                int firstItemIndex      = rowIndex * 3;
                var boundsForCurrentRow = CalculateLayoutBoundsForRow(rowIndex);

                for (int columnIndex = 0; columnIndex < 3; columnIndex++)
                {
                    var index     = firstItemIndex + columnIndex;
                    var rect      = boundsForCurrentRow[index % 3];
                    var container = virtualizingContext.GetOrCreateElementAt(index);
                    container.Measure(new Size(boundsForCurrentRow[columnIndex].Width, boundsForCurrentRow[columnIndex].Height));
                    state.LayoutRects.Add(boundsForCurrentRow[columnIndex]);
                }
            }

            // estimate the extent by finding the last item and getting its bottom/right position
            var extentHeight = ((int)(context.ItemCount / 3) - 1) * (this.MinItemSize.Height + this.RowSpacing) + this.MinItemSize.Height;

            // Report a desired size for the layout
            return(new Size(this.MinItemSize.Width * 4 + this.ItemSpacing * 2, extentHeight));
        }
예제 #24
0
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var viewport = context.RealizationRect;

            DebugTrace("MeasureOverride: Viewport " + viewport);

            // Remove bounds for elements that are now outside the viewport.
            // Proactive recycling elements means we can reuse it during this measure pass again.
            RemoveCachedBoundsOutsideViewport(viewport);

            // Find the index of the element to start laying out from - the anchor
            int startIndex = GetStartIndex(context, availableSize);

            // Measure and layout elements starting from the start index, forward and backward.
            Generate(context, availableSize, startIndex, forward: true);
            Generate(context, availableSize, startIndex, forward: false);

            // Estimate the extent size. Note that this can have a non 0 origin.
            m_lastExtent         = EstimateExtent(context, availableSize);
            context.LayoutOrigin = new Point(m_lastExtent.X, m_lastExtent.Y);
            return(new Size(m_lastExtent.Width, m_lastExtent.Height));
        }
예제 #25
0
        protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
        {
            // The data collection has changed, so the bounds of all the indices are not valid anymore.
            // We need to re-evaluate all the bounds and cache them during the next measure.
            switch (args.Action)
            {
            case NotifyCollectionChangedAction.Replace:

                this.cachedBoundsInvalid = true;
                this.InvalidateArrange();
                break;

            default:
                this._rowCachedBounds.Clear();
                this._rowHeight.Clear();
                this._rowXOffSet.Clear();
                this.m_cachedBounds.Clear();
                this.m_firstIndex        = this.m_lastIndex = 0;
                this.cachedBoundsInvalid = true;
                this.InvalidateMeasure();
                break;
            }
        }
예제 #26
0
        private void Generate(VirtualizingLayoutContext context, Size availableSize, int anchorDataIndex, bool forward)
        {
            // Generate forward or backward from anchorIndex until we hit the end of the viewport
            int step = forward ? 1 : -1;
            int previousDataIndex = anchorDataIndex;
            int currentDataIndex  = previousDataIndex + step;
            var viewport          = context.RealizationRect;

            while (IsDataIndexValid(currentDataIndex, context.ItemCount) &&
                   ShouldContinueFillingUpSpace(previousDataIndex, forward, viewport))
            {
                EnsureRealized(currentDataIndex);
                DebugTrace("Measuring " + currentDataIndex);
                var  desiredSize    = MeasureElement(context, currentDataIndex, availableSize);
                var  previousBounds = GetCachedBoundsForDataIndex(previousDataIndex);
                Rect currentBounds  = new Rect(0,
                                               forward ? previousBounds.Y + previousBounds.Height : previousBounds.Y - desiredSize.Height,
                                               availableSize.Width,
                                               desiredSize.Height);
                SetCachedBoundsForDataIndex(currentDataIndex, currentBounds);
                previousDataIndex = currentDataIndex;
                currentDataIndex += step;
            }
        }
 protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
 {
     return(ArrangeLayoutFunc != null?ArrangeLayoutFunc(finalSize, context) : default(Size));
 }
 protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
 {
     return(MeasureLayoutFunc != null?MeasureLayoutFunc(availableSize, context) : default(Size));
 }
예제 #29
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));
        }
예제 #30
0
        protected override FlowLayoutAnchorInfo GetAnchorForRealizationRect(Size availableSize, VirtualizingLayoutContext context)
        {
            var anchorInfo = base.GetAnchorForRealizationRect(availableSize, context);

            return(GetAnchorForRealizationRectFunc != null?GetAnchorForRealizationRectFunc(availableSize, context, anchorInfo) : anchorInfo);
        }