public void SetContext(VirtualizingLayoutContext virtualContext) => _context = virtualContext;
/// <summary> /// Provides the behavior for the "Measure" pass of the layout cycle. Classes can override /// this method to define their own "Measure" pass behavior. /// </summary> /// <param name="context"> /// The context object that facilitates communication between the layout and its host /// container. /// </param> /// <param name="availableSize"> /// The available size that this object can give to child objects. Infinity can be /// specified as a value to indicate that the object will size to whatever content is /// available. /// </param> /// <returns> /// The size that this object determines it needs during layout, based on its calculations /// of the allocated sizes for child objects or based on other considerations such as a /// fixed container size. /// </returns> protected internal abstract Size MeasureOverride( VirtualizingLayoutContext context, Size availableSize);
/// <summary> /// When implemented in a derived class, provides the behavior for the "Arrange" pass of /// layout. Classes can override this method to define their own "Arrange" pass behavior. /// </summary> /// <param name="context"> /// The context object that facilitates communication between the layout and its host /// container. /// </param> /// <param name="finalSize"> /// The final area within the container that this object should use to arrange itself and /// its children. /// </param> /// <returns>The actual size that is used after the element is arranged in layout.</returns> protected internal virtual Size ArrangeOverride( VirtualizingLayoutContext context, Size finalSize) => finalSize;
/// <summary> /// Notifies the layout when the data collection assigned to the container element (Items) /// has changed. /// </summary> /// <param name="context"> /// The context object that facilitates communication between the layout and its host /// container. /// </param> /// <param name="source">The data source.</param> /// <param name="args">Data about the collection change.</param> /// <remarks> /// Override <see cref="OnItemsChangedCore(VirtualizingLayoutContext, object, NotifyCollectionChangedEventArgs)"/> /// to provide the behavior for this method in a derived class. /// </remarks> public void OnItemsChanged( VirtualizingLayoutContext context, object?source, NotifyCollectionChangedEventArgs args) => OnItemsChangedCore(context, source, args);
/// <summary> /// When overridden in a derived class, removes any state the layout previously stored on /// the ILayoutable container. /// </summary> /// <param name="context"> /// The context object that facilitates communication between the layout and its host /// container. /// </param> protected internal virtual void UninitializeForContextCore(VirtualizingLayoutContext context) { }
/// <inheritdoc /> protected internal override void UninitializeForContextCore(VirtualizingLayoutContext context) { context.LayoutState = null; base.UninitializeForContextCore(context); }
/// <summary> /// Notifies the layout when the data collection assigned to the container element (Items) /// has changed. /// </summary> /// <param name="context"> /// The context object that facilitates communication between the layout and its host /// container. /// </param> /// <param name="source">The data source.</param> /// <param name="args">Data about the collection change.</param> protected internal virtual void OnItemsChangedCore( VirtualizingLayoutContext context, object?source, NotifyCollectionChangedEventArgs args) => InvalidateMeasure();
/// <inheritdoc /> protected internal 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)); }
/// <inheritdoc /> protected internal override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { if (context.ItemCount > 0) { var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); var realizationBounds = new UvBounds(Orientation, context.RealizationRect); var state = (WrapLayoutState)context.LayoutState !; bool Arrange(WrapItem item, bool isLast = false) { if (item.Measure.HasValue == false) { return(false); } if (item.Position == null) { return(false); } var desiredMeasure = item.Measure.Value; if (desiredMeasure.U == 0) { return(true); // if an item is collapsed, avoid adding the spacing } UvMeasure position = item.Position.Value; // Stretch the last item to fill the available space if (isLast) { desiredMeasure.U = parentMeasure.U - position.U; } if (((position.V + desiredMeasure.V) >= realizationBounds.VMin) && (position.V <= realizationBounds.VMax)) { // place the item var child = context.GetOrCreateElementAt(item.Index); if (Orientation == Orientation.Horizontal) { child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V)); } else { child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U)); } } else if (position.V > realizationBounds.VMax) { return(false); } return(true); } for (var i = 0; i < context.ItemCount; i++) { bool continueArranging = Arrange(state.GetItemAt(i)); if (continueArranging == false) { break; } } } return(finalSize); }
public void InitializeForContext(VirtualizingLayoutContext context, IFlowLayoutAlgorithmDelegates callbacks) { _algorithmCallbacks = callbacks; _context = context; _elementManager.SetContext(context); }
internal void InitializeForContext(VirtualizingLayoutContext context, IFlowLayoutAlgorithmDelegates callbacks) { FlowAlgorithm.InitializeForContext(context, callbacks); context.LayoutState = this; }
internal void UninitializeForContext(VirtualizingLayoutContext context) { FlowAlgorithm.UninitializeForContext(context); }
internal VirtualizingLayoutContext GetVirtualizingContextAdapter() => _contextAdapter ?? (_contextAdapter = new LayoutContextAdapter(this));
public WrapLayoutState(VirtualizingLayoutContext context) { this._context = context; }