internal void RecycleElementAt(int index)
        {
            UIElement element = _context.GetOrCreateElementAt(index);

            _context.RecycleElement(element);
        }
Пример #2
0
        /// <inheritdoc/>
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            if (context.ItemCount == 0)
            {
                return(new Size(availableSize.Width, 0));
            }

            if ((context.RealizationRect.Width == 0) && (context.RealizationRect.Height == 0))
            {
                return(new Size(availableSize.Width, 0.0));
            }

            var state = (StaggeredLayoutState)context.LayoutState;

            double availableWidth  = availableSize.Width;
            double availableHeight = availableSize.Height;

            double columnWidth = Math.Min(DesiredColumnWidth, availableWidth);

            if (columnWidth != state.ColumnWidth)
            {
                // The items will need to be remeasured
                state.Clear();
            }

            state.ColumnWidth = Math.Min(DesiredColumnWidth, availableWidth);
            int numColumns = Math.Max(1, (int)Math.Floor(availableWidth / state.ColumnWidth));

            // adjust for column spacing on all columns expect the first
            double totalWidth = state.ColumnWidth + ((numColumns - 1) * (state.ColumnWidth + ColumnSpacing));

            if (totalWidth > availableWidth)
            {
                numColumns--;
            }
            else if (double.IsInfinity(availableWidth))
            {
                availableWidth = totalWidth;
            }

            if (numColumns != state.NumberOfColumns)
            {
                // The items will not need to be remeasured, but they will need to go into new columns
                state.ClearColumns();
            }

            if (RowSpacing != state.RowSpacing)
            {
                // If the RowSpacing changes the height of the rows will be different.
                // The columns stores the height so we'll want to clear them out to
                // get the proper height
                state.ClearColumns();
                state.RowSpacing = RowSpacing;
            }

            var columnHeights  = new double[numColumns];
            var itemsPerColumn = new int[numColumns];
            var deadColumns    = new HashSet <int>();

            for (int i = 0; i < context.ItemCount; i++)
            {
                var columnIndex = GetColumnIndex(columnHeights);

                bool          measured = false;
                StaggeredItem item     = state.GetItemAt(i);
                if (item.Height == 0)
                {
                    // Item has not been measured yet. Get the element and store the values
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(new Size(state.ColumnWidth, availableHeight));
                    item.Height = item.Element.DesiredSize.Height;
                    measured    = true;
                }

                double spacing = itemsPerColumn[columnIndex] > 0 ? RowSpacing : 0;
                item.Top = columnHeights[columnIndex] + spacing;
                double bottom = item.Top + item.Height;
                columnHeights[columnIndex] = bottom;
                itemsPerColumn[columnIndex]++;
                state.AddItemToColumn(item, columnIndex);

                if (bottom < context.RealizationRect.Top)
                {
                    // The bottom of the element is above the realization area
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }
                }
                else if (item.Top > context.RealizationRect.Bottom)
                {
                    // The top of the element is below the realization area
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }

                    deadColumns.Add(columnIndex);
                }
                else if (measured == false)
                {
                    // We ALWAYS want to measure an item that will be in the bounds
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(new Size(state.ColumnWidth, availableHeight));
                    if (item.Height != item.Element.DesiredSize.Height)
                    {
                        // this item changed size; we need to recalculate layout for everything after this
                        state.RemoveFromIndex(i + 1);
                        item.Height = item.Element.DesiredSize.Height;
                        columnHeights[columnIndex] = item.Top + item.Height;
                    }
                }

                if (deadColumns.Count == numColumns)
                {
                    break;
                }
            }

            double desiredHeight = state.GetHeight();

            return(new Size(availableWidth, desiredHeight));
        }
        /// <inheritdoc />
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var totalMeasure      = UvMeasure.Zero;
            var parentMeasure     = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
            var spacingMeasure    = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
            var position          = UvMeasure.Zero;

            var state = (WrapLayoutState)context.LayoutState;

            if (state.Orientation != Orientation)
            {
                state.SetOrientation(Orientation);
            }

            if (spacingMeasure.Equals(state.Spacing) == false)
            {
                state.ClearPositions();
                state.Spacing = spacingMeasure;
            }

            if (state.AvailableU != parentMeasure.U)
            {
                state.ClearPositions();
                state.AvailableU = parentMeasure.U;
            }

            double currentV = 0;

            for (int i = 0; i < context.ItemCount; i++)
            {
                bool     measured = false;
                WrapItem item     = state.GetItemAt(i);
                if (item.Measure == null)
                {
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(availableSize);
                    item.Measure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
                    measured     = true;
                }

                UvMeasure currentMeasure = item.Measure.Value;
                if (currentMeasure.U == 0)
                {
                    continue; // ignore collapsed items
                }

                if (item.Position == null)
                {
                    if (parentMeasure.U < position.U + currentMeasure.U)
                    {
                        // New Row
                        position.U  = 0;
                        position.V += currentV + spacingMeasure.V;
                        currentV    = 0;
                    }

                    item.Position = position;
                }

                position = item.Position.Value;

                double vEnd = position.V + currentMeasure.V;
                if (vEnd < realizationBounds.VMin)
                {
                    // Item is "above" the bounds
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }
                }
                else if (position.V > realizationBounds.VMax)
                {
                    // Item is "below" the bounds.
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }

                    // We don't need to measure anything below the bounds
                    break;
                }
                else if (measured == false)
                {
                    // Always measure elements that are within the bounds
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(availableSize);

                    currentMeasure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
                    if (currentMeasure.Equals(item.Measure) == false)
                    {
                        // this item changed size; we need to recalculate layout for everything after this
                        state.RemoveFromIndex(i + 1);
                        item.Measure = currentMeasure;

                        // did the change make it go into the new row?
                        if (parentMeasure.U < position.U + currentMeasure.U)
                        {
                            // New Row
                            position.U  = 0;
                            position.V += currentV + spacingMeasure.V;
                            currentV    = 0;
                        }

                        item.Position = position;
                    }
                }

                position.U += currentMeasure.U + spacingMeasure.U;
                currentV    = Math.Max(currentMeasure.V, currentV);
            }

            // update value with the last line
            // if the the last loop is(parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it
            // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
            // for the last condition it is zeros so adding it will make no difference
            // this way is faster than an if condition in every loop for checking the last item
            totalMeasure.U = parentMeasure.U;

            // Propagating an infinite size causes a crash. This can happen if the parent is scrollable and infinite in the opposite
            // axis to the panel. Clearing to zero prevents the crash.
            // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that wont crash.
            if (double.IsInfinity(totalMeasure.U))
            {
                totalMeasure.U = 0.0;
            }

            totalMeasure.V = state.GetHeight();

            totalMeasure.U = Math.Ceiling(totalMeasure.U);
            return(Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U));
        }
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var requiredSize = new Size(Padding.Left + Padding.Right, Padding.Top + Padding.Bottom);

            if (context.ItemCount == 0 ||
                context.RealizationRect.Width == 0 ||
                context.RealizationRect.Height == 0)
            {
                return(requiredSize);
            }

            var state      = (AutoFillLayoutState)context.LayoutState;
            var clientSize = new Size(
                availableSize.Width - Padding.Left - Padding.Right,
                availableSize.Height - Padding.Top - Padding.Bottom);

            //Save layout properties
            //If changed every thing need redo
            if (state.SavePropertiesIfChange(Orientation, Padding,
                                             HorizontalSpacing, VerticalSpacing, availableSize))
            {
                state.Reset();
            }

            if (!state.Initialized)
            {
                if (Orientation == Orientation.Horizontal)
                {
                    state.Initialize(
                        new Rect(Padding.Left, Padding.Top,
                                 clientSize.Width + HorizontalSpacing, double.PositiveInfinity)
                        );
                }
                else
                {
                    state.Initialize(
                        new Rect(Padding.Left, Padding.Top,
                                 double.PositiveInfinity, clientSize.Height + VerticalSpacing)
                        );
                }
            }

            for (int i = 0; i < context.ItemCount; i++)
            {
                var item = state.GetOrCreateItemAt(i);

                bool measured = false;

                if (item.Bounds.IsEmpty())//measure empty
                {
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(clientSize);
                    item.Width  = item.Element.DesiredSize.Width;
                    item.Height = item.Element.DesiredSize.Height;
                    state.FitItem(item);
                    measured = true;
                }

                item.ShouldDisplay = context.RealizationRect.IsIntersect(item.Bounds);
                if (!item.ShouldDisplay)
                {
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }
                }
                else if (!measured)//measure in view rect
                {
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(clientSize);
                    var childSize = item.Element.DesiredSize;
                    if (item.Width != childSize.Width || item.Height != childSize.Height)  //size changed
                    {
                        item.Width  = childSize.Width;
                        item.Height = childSize.Height;
                        state.RemoveItemsFrom(i + 1);//remove after this
                        state.FitItem(item);
                    }
                }
            }

            var size = state.GetTotalSize();

            //var size = state.GetVirtualizedSize();
            requiredSize.Width  += size.Width;
            requiredSize.Height += size.Height;
            return(requiredSize);
        }