protected override void UninitializeForContextCore(VirtualizingLayoutContext context) { base.UninitializeForContextCore(context); // clear any state context.LayoutState = null; }
protected override void InitializeForContextCore(VirtualizingLayoutContext context) { base.InitializeForContextCore(context); var state = context.LayoutState as ActivityFeedLayoutState; if (state == null) { // 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(); } }
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); }
protected internal virtual void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args) { InvalidateMeasure(); }
protected virtual FlowLayoutAnchorInfo GetAnchorForRealizationRect(Size availableSize, VirtualizingLayoutContext context) { int anchorIndex = -1; double offset = double.NaN; // Constants int itemsCount = context.ItemCount; if (itemsCount > 0) { var realizationRect = context.RealizationRect; var state = context.LayoutState; var flowState = GetAsFlowState(state); var lastExtent = flowState.FlowAlgorithm.LastExtent; double averageItemsPerLine = 0; double averageLineSize = GetAverageLineInfo(availableSize, context, flowState, out averageItemsPerLine) + LineSpacing; MUX_ASSERT(averageItemsPerLine != 0); double extentMajorSize = MajorSize(lastExtent) == 0 ? (itemsCount / averageItemsPerLine) * averageLineSize : MajorSize(lastExtent); if (itemsCount > 0 && MajorSize(realizationRect) > 0 && DoesRealizationWindowOverlapExtent(realizationRect, MinorMajorRect((float)MinorStart(lastExtent), (float)MajorStart(lastExtent), (float)Minor(availableSize), (float)(extentMajorSize)))) { double realizationWindowStartWithinExtent = MajorStart(realizationRect) - MajorStart(lastExtent); int lineIndex = Math.Max(0, (int)(realizationWindowStartWithinExtent / averageLineSize)); anchorIndex = (int)(lineIndex * averageItemsPerLine); // Clamp it to be within valid range anchorIndex = Math.Max(0, Math.Min(itemsCount - 1, anchorIndex)); offset = lineIndex * averageLineSize + MajorStart(lastExtent); } } return(new FlowLayoutAnchorInfo(anchorIndex, offset)); }
public void Algorithm_OnLineArranged(int startIndex, int countInLine, double lineSize, VirtualizingLayoutContext context) { }
FlowLayoutAnchorInfo IFlowLayoutAlgorithmDelegates.Algorithm_GetAnchorForRealizationRect(Size availableSize, VirtualizingLayoutContext context) { return(GetAnchorForRealizationRect(availableSize, context)); }
Size IFlowLayoutAlgorithmDelegates.Algorithm_GetMeasureSize(int index, Size availableSize, VirtualizingLayoutContext context) { return(availableSize); }
protected internal override void InitializeForContextCore(VirtualizingLayoutContext context) { var state = context.LayoutState; UniformGridLayoutState gridState = null; if (state is { })
protected internal override void UninitializeForContextCore(VirtualizingLayoutContext context) { var flowState = GetAsFlowState(context.LayoutState); flowState.UninitializeForContext(context); }
Size IFlowLayoutAlgorithmDelegates.Algorithm_GetProvisionalArrangeSize(int index, Size measureSize, Size desiredSize, VirtualizingLayoutContext context) { return(GetProvisionalArrangeSize(index, measureSize, desiredSize)); }
FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) { return(GetAsFlowState(context.LayoutState).FlowAlgorithm); }
protected virtual Rect GetExtent( Size availableSize, VirtualizingLayoutContext context, UIElement firstRealized, int firstRealizedItemIndex, Rect firstRealizedLayoutBounds, UIElement lastRealized, int lastRealizedItemIndex, Rect lastRealizedLayoutBounds) { var extent = default(Rect); int itemsCount = context.ItemCount; if (itemsCount > 0) { var availableSizeMinor = (float)Minor(availableSize); var state = context.LayoutState; var flowState = GetAsFlowState(state); double averageItemsPerLine = 0; double averageLineSize = GetAverageLineInfo(availableSize, context, flowState, out averageItemsPerLine) + LineSpacing; MUX_ASSERT(averageItemsPerLine != 0); if (firstRealized != null) { MUX_ASSERT(lastRealized != null); int linesBeforeFirst = (int)(firstRealizedItemIndex / averageItemsPerLine); double extentMajorStart = MajorStart(firstRealizedLayoutBounds) - linesBeforeFirst * averageLineSize; SetMajorStart(ref extent, extentMajorStart); int remainingItems = itemsCount - lastRealizedItemIndex - 1; int remainingLinesAfterLast = (int)((remainingItems / averageItemsPerLine)); double extentMajorSize = MajorEnd(lastRealizedLayoutBounds) - MajorStart(extent) + remainingLinesAfterLast * averageLineSize; SetMajorSize(ref extent, extentMajorSize); // If the available size is infinite, we will have realized all the items in one line. // In that case, the extent in the non virtualizing direction should be based on the // right/bottom of the last realized element. SetMinorSize(ref extent, availableSizeMinor.IsFinite() ? availableSizeMinor : Math.Max(0.0f, MinorEnd(lastRealizedLayoutBounds))); } else { var lineSpacing = LineSpacing; var minItemSpacing = MinItemSpacing; // We dont have anything realized. make an educated guess. int numLines = (int)Math.Ceiling(itemsCount / averageItemsPerLine); extent = availableSizeMinor.IsFinite() ? MinorMajorRect(0, 0, availableSizeMinor, Math.Max(0.0f, (float)(numLines * averageLineSize - lineSpacing))) : MinorMajorRect( 0, 0, Math.Max(0.0f, (float)((Minor(flowState.SpecialElementDesiredSize) + minItemSpacing) * itemsCount - minItemSpacing)), Math.Max(0.0f, (float)(averageLineSize - lineSpacing))); REPEATER_TRACE_INFO("%*s: \tEstimating extent with no realized elements. \n", context.Indent, LayoutId); } REPEATER_TRACE_INFO( "%*s: \tExtent is {%.0f,%.0f}. Based on average line size {%.0f} and average items per line {%.0f}. \n", context.Indent, LayoutId, extent.Width, extent.Height, averageLineSize, averageItemsPerLine); } else { MUX_ASSERT(firstRealizedItemIndex == -1); MUX_ASSERT(lastRealizedItemIndex == -1); REPEATER_TRACE_INFO("%*s: \tExtent is {%.0f,%.0f}. ItemCount is 0 \n", context.Indent, LayoutId, extent.Width, extent.Height); } return(extent); }
protected virtual FlowLayoutAnchorInfo GetAnchorForTargetElement(int targetIndex, Size availableSize, VirtualizingLayoutContext context) { double offset = double.NaN; int index = -1; int itemsCount = context.ItemCount; if (targetIndex >= 0 && targetIndex < itemsCount) { index = targetIndex; var state = context.LayoutState; var flowState = GetAsFlowState(state); double averageItemsPerLine = 0; double averageLineSize = GetAverageLineInfo(availableSize, context, flowState, out averageItemsPerLine) + LineSpacing; int lineIndex = (int)(targetIndex / averageItemsPerLine); offset = lineIndex * averageLineSize + MajorStart(flowState.FlowAlgorithm.LastExtent); } return(new FlowLayoutAnchorInfo(index, offset)); }
public ChildrenCollection(VirtualizingLayoutContext context) { m_context = context; }
protected internal override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args) { GetFlowAlgorithm(context).OnItemsSourceChanged(source, args, context); // Always invalidate layout to keep the view accurate. InvalidateLayout(); }
public void SetContext(VirtualizingLayoutContext virtualContext) { m_context = virtualContext; }
Size IFlowLayoutAlgorithmDelegates.Algorithm_GetProvisionalArrangeSize(int index, Size measureSize, Size desiredSize, VirtualizingLayoutContext context) { var measureSizeMinor = Minor(measureSize); return(MinorMajorSize( (float)(measureSizeMinor.IsFinite() ? Math.Max(measureSizeMinor, Minor(desiredSize)) : Minor(desiredSize)), (float)Major(desiredSize))); }
public void OnItemsSourceChanged(object source, NotifyCollectionChangedEventArgs args, VirtualizingLayoutContext context) { m_elementManager.DataSourceChanged(source, args); m_collectionChangePending = true; }
FlowLayoutAnchorInfo IFlowLayoutAlgorithmDelegates.Algorithm_GetAnchorForTargetElement(int targetIndex, Size availableSize, VirtualizingLayoutContext context) { double offset = double.NaN; int index = -1; int itemsCount = context.ItemCount; if (targetIndex >= 0 && targetIndex < itemsCount) { index = targetIndex; var state = GetAsStackState(context.LayoutState); double averageElementSize = GetAverageElementSize(availableSize, context, state) + m_itemSpacing; offset = index * averageElementSize + MajorStart(state.FlowAlgorithm.LastExtent); } return(new FlowLayoutAnchorInfo(index, offset)); }
public void InitializeForContext(VirtualizingLayoutContext context, IFlowLayoutAlgorithmDelegates callbacks) { m_algorithmCallbacks = callbacks; m_context = context; m_elementManager.SetContext(context); }
FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => GetAsStackState(context.LayoutState).FlowAlgorithm;
protected internal virtual void UninitializeForContextCore(VirtualizingLayoutContext context) { }
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)); }
protected internal virtual Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { throw new NotImplementedException(); }
protected internal virtual Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { // Do not throw. If the layout decides to arrange its // children during measure, then an ArrangeOverride is not required. return(finalSize); }
public void UninitializeForContext(VirtualizingLayoutContext context) { m_flowAlgorithm.UninitializeForContext(context); }