internal void RecycleElementAt(int index) { UIElement element = _context.GetOrCreateElementAt(index); _context.RecycleElement(element); }
/// <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); }