internal override RadVirtualizingDataControlItem GetContainerForItem(IDataSourceItem item, int insertAt) { RadVirtualizingDataControlItem container = base.GetContainerForItem(item, insertAt); this.allItemsExtent += this.GetItemExtent(container); return(container); }
internal override void OnAfterItemRemovedAnimationEnded(SingleItemAnimationContext context) { double startingOffset = context.AssociatedItem.CurrentOffset; double offset = context.RealizedLength; // Apply the aggregated height correction to all affected visual items reamining on the viewport for (int i = 0; i < this.owner.realizedItems.Count; i++) { RadVirtualizingDataControlItem firstItem = this.owner.realizedItems[i]; if (firstItem.CurrentOffset > startingOffset) { if (firstItem.previous == null || (firstItem.previous != null && firstItem.previous.CurrentOffset + this.GetItemLength(firstItem.previous) <= firstItem.CurrentOffset - offset)) { this.SetItemOffset(firstItem, firstItem.CurrentOffset - offset); } else { break; } } } this.TranslateRemoveAnimatedItemsWithOffset(startingOffset, -offset); if (this.owner.IsLoaded) { this.ManageLowerViewport(false); this.CheckBottomScrollableBounds(); } }
internal override void ReorderViewportItemsOnItemRemoved(int removedAt, RadVirtualizingDataControlItem removedContainer) { double correctionLength = this.GetItemLength(removedContainer); if (this.reorderMode == CollectionChangeItemReorderMode.MoveItemsDown) { // Apply the aggregated height correction to all affected visual items reamining on the viewport for (int i = removedAt; i < this.owner.realizedItems.Count; i++) { RadVirtualizingDataControlItem itemToOffset = this.owner.realizedItems[i]; double currentVerticalOffset = itemToOffset.CurrentOffset; this.SetItemOffset(itemToOffset, currentVerticalOffset - correctionLength); } } else { // Apply the aggregated height correction to all affected visual items reamining on the viewport for (int i = 0; i < removedAt; i++) { RadVirtualizingDataControlItem itemToOffset = this.owner.realizedItems[i]; double currentVerticalOffset = itemToOffset.CurrentOffset; this.SetItemOffset(itemToOffset, currentVerticalOffset + correctionLength); } } }
internal override void ReorderViewportItemsOnItemReplaced(RadVirtualizingDataControlItem replacedItem) { if (this.reorderMode == CollectionChangeItemReorderMode.MoveItemsDown) { RadVirtualizingDataControlItem nextItem = replacedItem.next; while (nextItem != null) { this.SetItemOffset(nextItem, nextItem.previous.CurrentOffset + this.GetItemLength(nextItem.previous)); nextItem = nextItem.next; } } else { RadVirtualizingDataControlItem processedItem = replacedItem; while (processedItem != null) { if (processedItem.next != null) { this.SetItemOffset(processedItem, processedItem.next.CurrentOffset - this.GetItemLength(processedItem)); } processedItem = processedItem.previous; } } }
private void SynchItemOffsetInRow(WrapRow row) { RadVirtualizingDataControlItem firstItem = row.firstItem; switch (this.orientationCache) { case Orientation.Horizontal: while (true) { firstItem.SetVerticalOffset(row.rowOffset); firstItem = firstItem.next; if (firstItem.wrapRow != row) { break; } } break; case Orientation.Vertical: while (true) { firstItem.SetHorizontalOffset(row.rowOffset); firstItem = firstItem.next; if (firstItem.wrapRow != row) { break; } } break; } }
internal override void ResetRealizationStartWhenLowerUIBufferRecycled(double position) { double bottomDifference = position - this.GetItemLength(this.owner.lastItemCache); if (bottomDifference > this.bottomVirtualizationThreshold + this.ScrollOffset) { int rowCount = (int)Math.Round(bottomDifference / this.averageItemLength, 0); int itemCount = rowCount * this.stackCount; RadVirtualizingDataControlItem firstRealizedDataItem = this.owner.FirstRealizedDataItem; int currentFirstItemIndex = 0; if (firstRealizedDataItem != null) { currentFirstItemIndex = Math.Max(firstRealizedDataItem.associatedDataItem.Index - itemCount, 0); } IDataSourceItem newDataItem = firstRealizedDataItem.associatedDataItem; while (newDataItem.Index > currentFirstItemIndex) { newDataItem = newDataItem.Previous; Debug.Assert(newDataItem != null, "The currentLastItemIndex should be within the bounds of the flattened view of the collection."); } while (this.owner.realizedItems.Count > 0) { this.RecycleItem(this.owner.realizedItems[0]); } var newRealized = this.GetContainerForItem(newDataItem, false); double currentTop = this.ScrollOffset; this.PositionBottomRealizedItem(this.owner.lastItemCache, ref currentTop); } }
internal override void ReorderViewportItemsOnItemReplaced(RadVirtualizingDataControlItem replacedItem) { RadVirtualizingDataControlItem pivotContainer = replacedItem.next; int containersToSkip = 0; //TODO: rearange items. if (pivotContainer != null) { containersToSkip = Math.Max(this.stackCount - this.owner.realizedItems.IndexOf(pivotContainer), 0); } while (pivotContainer != null) { if (containersToSkip > 0) { containersToSkip--; continue; } this.slotsRepository.Remove(pivotContainer.associatedDataItem.Index); pivotContainer = pivotContainer.next; } this.ReorderViewportOnItemsChanged(); }
private bool CheckEnoughSpaceForItemInRow(WrapRow row, RadVirtualizingDataControlItem item, bool addingAtStart) { switch (this.orientationCache) { case Orientation.Horizontal: if (addingAtStart) { return(this.owner.availableWidth - (row.lastItem.horizontalOffsetCache + row.lastItem.width - row.firstItem.horizontalOffsetCache) >= item.width); } else { return(row.firstItem.horizontalOffsetCache >= item.width); } case Orientation.Vertical: if (addingAtStart) { return(this.owner.availableHeight - (row.lastItem.verticalOffsetCache + row.lastItem.height - row.firstItem.verticalOffsetCache) >= item.height); } else { return(row.firstItem.verticalOffsetCache >= item.height); } } return(false); }
internal override void OnOrientationChanged(Orientation newValue) { base.OnOrientationChanged(newValue); if (this.owner == null || !this.owner.IsTemplateApplied) { return; } if (this.owner.GetItemCount() > 0) { this.owner.StopAllAddedAnimations(); this.owner.StopAllRemovedAnimations(); while (this.owner.realizedItems.Count > 0) { RadVirtualizingDataControlItem lastItem = this.owner.realizedItems[this.owner.realizedItems.Count - 1]; lastItem.SetVerticalOffset(0); lastItem.SetHorizontalOffset(0); this.owner.RecycleLastItem(); } this.owner.BeginAsyncBalance(); this.owner.BalanceVisualSpace(); } }
/// <summary> /// Determines whether the specified data item is currently visible. /// </summary> /// <param name="dataItem">The data item.</param> /// <param name="includePartiallyVisibleItems"> /// If this parameter is set to <c>true</c>, then the partially visible items will also be included. /// </param> public bool IsItemInViewport(object dataItem, bool includePartiallyVisibleItems = true) { if (!this.IsOperational()) { return(false); } RadVirtualizingDataControlItem container = this.virtualizationStrategy.GetTopVisibleContainer(); int iterationStart = container.associatedDataItem.Index - this.firstItemCache.associatedDataItem.Index; double bottomViewportEdge = this.virtualizationStrategy.ViewportLength + this.virtualizationStrategy.ScrollOffset; for (int i = iterationStart; i < this.realizedItems.Count; i++) { container = this.realizedItems[i]; var itemTop = this.virtualizationStrategy.GetItemRelativeOffset(container); if (itemTop < bottomViewportEdge) { if (!includePartiallyVisibleItems && (itemTop < this.virtualizationStrategy.ScrollOffset || itemTop + this.virtualizationStrategy.GetItemLength(container) > bottomViewportEdge)) { continue; } if (dataItem.Equals(container.associatedDataItem.Value) && container.Visibility == Visibility.Visible) { return(true); } } else { break; } } return(false); }
private SingleItemAnimationContext GetAnimationContextForTarget(RadVirtualizingDataControlItem target, bool lookInAdded) { if (lookInAdded) { foreach (SingleItemAnimationContext c in this.scheduledAddAnimations) { if (c.AssociatedItem == target) { return(c); } } } else { foreach (SingleItemAnimationContext c in this.scheduledRemoveAnimations) { if (c.AssociatedItem == target) { return(c); } } } return(null); }
internal override void ReorderViewportItemsOnItemReplaced(RadVirtualizingDataControlItem replacedItem) { WrapRow parentRow = replacedItem.wrapRow.firstItem == replacedItem ? replacedItem.wrapRow.previous != null ? replacedItem.wrapRow.previous : replacedItem.wrapRow : replacedItem.wrapRow; parentRow.rowLength = 0; this.ReorderViewportItemsStartingAtRow(parentRow); }
internal override RadVirtualizingDataControlItem GetContainerForItem(IDataSourceItem item, int insertAt) { RadVirtualizingDataControlItem container = base.GetContainerForItem(item, insertAt); this.realizedItemsLength += this.GetItemLength(container); return(container); }
internal virtual double GetItemRowOffset(RadVirtualizingDataControlItem item) { if (this.orientationCache == Orientation.Vertical) { return(item.verticalOffsetCache); } return(item.horizontalOffsetCache); }
internal RadVirtualizingDataControlItem GenerateContainerForItem(IDataSourceItem item) { RadVirtualizingDataControlItem cp = this.GetContainerForItemOverride(); this.OnContainerStateChanged(cp, item, ItemState.Realizing); this.itemsPanel.Children.Add(cp); this.PrepareContainerForItemOverride(cp, item); return(cp); }
internal virtual double GetItemLength(RadVirtualizingDataControlItem item) { if (this.LayoutOrientation == Orientation.Horizontal) { return(item.width); } return(item.height); }
internal void OnContainerSizeChanged(RadVirtualizingDataControlItem container, Size newSize, Size oldSize) { if (this.GetItemCount() == 0) { return; } this.virtualizationStrategy.OnContainerSizeChanged(container, newSize, oldSize); }
internal override bool PositionBottomRealizedItem(RadVirtualizingDataControlItem item, ref double visibleItemsBottom) { RadVirtualizingDataControlItem realizedItem = item; double offset = realizedItem.previous != null ? realizedItem.previous.CurrentOffset + this.GetItemLength(realizedItem.previous) : this.ScrollOffset; this.SetItemOffset(realizedItem, offset); visibleItemsBottom += this.GetItemLength(realizedItem); return(true); }
internal override void ReorderViewportItemsOnItemAddedOnTop(IDataSourceItem addedItem) { RadVirtualizingDataControlItem firstRealized = this.owner.firstItemCache; IDataSourceItem prev = this.owner.GetItemBefore(firstRealized.associatedDataItem); RadVirtualizingDataControlItem newFirst = this.GetContainerForItem(prev, false); newFirst.wrapRow = firstRealized.wrapRow; newFirst.wrapRow.firstItem = newFirst; this.ReorderViewportItemsStartingAtRow(newFirst.wrapRow); }
internal virtual void PlaySingleItemRemovedAnimation(RadVirtualizingDataControlItem item) { int realizedIndex = item.associatedDataItem.Index - this.owner.firstItemCache.associatedDataItem.Index; RadAnimationManager.Play(item, this.owner.itemRemovedAnimationCache); this.owner.scheduledRemoveAnimations.Add(new SingleItemAnimationContext() { AssociatedItem = item, RealizedLength = this.GetItemLength(item), RealizedIndex = realizedIndex }); }
internal virtual void RefreshViewportOnItemRemoved(int startIndex, IDataSourceItem removedItem) { if (this.generatedItemsLength.ContainsKey(removedItem.Index)) { this.generatedItemsLength.Remove(removedItem.Index); } int firstRealizedIndex = this.owner.GetFirstItemCacheIndex(); int lastRealizedIndex = this.owner.GetLastItemCacheIndex(); int?listStartIndex = null; ////Check whether the change has occured among the currently realized items. if (startIndex >= firstRealizedIndex && startIndex <= lastRealizedIndex) { listStartIndex = startIndex; } ////If the change has occured among the realized items, update the screen if (listStartIndex.HasValue) { int iterationStartIndex = this.owner.GetItemRealizedIndexFromListSourceIndex(listStartIndex.Value, firstRealizedIndex); RadVirtualizingDataControlItem itemToRecycle = this.owner.realizedItems[iterationStartIndex]; if (this.owner.itemRemovedAnimationCache != null && (this.owner.itemAnimationModeCache & ItemAnimationMode.PlayOnRemove) != 0 && this.owner.CanPlayAnimationForItem(itemToRecycle, false)) { // If we have item remove animation defined, we recycle the item without hiding it and start the remove animation. this.owner.itemRemovedAnimationCache.ApplyInitialValues(itemToRecycle); this.owner.PlaySingleItemRemovedAnimation(itemToRecycle); this.RecycleItem(itemToRecycle, false); } else { ////Recycle the visual item associated with the removed data item this.owner.ClearContainerForItemInternal(itemToRecycle, itemToRecycle.associatedDataItem); this.ReorderViewportItemsOnItemRemoved(iterationStartIndex, itemToRecycle); } } else if (startIndex < firstRealizedIndex) { this.ReorderViewportItemsOnItemRemovedFromTop(removedItem); } ////If there are no more items reset the scroll offset if (this.owner.GetItemCount() == 0) { this.ScrollToOffset(0, null); return; } ////Balance the visual space if (this.owner.scheduledRemoveAnimations.Count == 0) { this.owner.BalanceVisualSpace(); } }
internal virtual void SetItemOffset(RadVirtualizingDataControlItem item, double offset) { if (this.LayoutOrientation == Orientation.Vertical) { item.SetVerticalOffset(offset); } else { item.SetHorizontalOffset(offset); } }
internal virtual void InvalidateItemOffset(RadVirtualizingDataControlItem item) { if (this.LayoutOrientation == Orientation.Vertical) { item.InvalidateVerticalOffset(); } else { item.InvalidateHorizontalOffset(); } }
/// <summary>Prepares the specified element to display the specified item. </summary> /// <param name="element">The element used to display the specified item.</param> /// <param name="item">The item to display.</param> protected virtual void PrepareContainerForItemOverride(RadVirtualizingDataControlItem element, IDataSourceItem item) { element.BindToDataItem(item); this.PrepareStyle(element, item); if (item.Value != RadListSource.UnsetObject) { this.PrepareDataItem(element, item); } }
private void TranslateRemoveAnimatedItemsWithOffset(double startingFrom, double offset) { foreach (SingleItemAnimationContext item in this.owner.scheduledRemoveAnimations) { RadVirtualizingDataControlItem associatedItem = item.AssociatedItem; if (associatedItem.CurrentOffset > startingFrom) { this.SetItemOffset(associatedItem, associatedItem.CurrentOffset + offset); } } }
internal virtual void RecycleItem(RadVirtualizingDataControlItem item, bool setVisibility) { if (item.scheduledForBatchAnimation) { if (this.owner.itemAddedAnimationCache != null) { this.owner.itemAddedAnimationCache.ClearAnimation(item); } } item.scheduledForBatchAnimation = false; IDataSourceItem associatedItem = item.associatedDataItem; this.owner.OnContainerStateChanged(item, associatedItem, ItemState.Recycling); item.ResetDataItemBinding(); if (setVisibility) { item.Visibility = Visibility.Collapsed; // item.SetHorizontalOffset(0); // item.SetVerticalOffset(0); } this.owner.realizedItems.Remove(item); this.owner.recycledItems.Enqueue(item); if (item.next != null) { item.next.previous = item.previous; } if (item.previous != null) { item.previous.next = item.next; } item.next = null; item.previous = null; int realizedItemsCount = this.owner.realizedItems.Count; if (this.owner.realizedItems.Count > 0) { this.owner.lastItemCache = this.owner.realizedItems[realizedItemsCount - 1]; this.owner.firstItemCache = this.owner.realizedItems[0]; } else { this.averageItemLength = 0; this.owner.lastItemCache = null; this.owner.firstItemCache = null; } this.owner.OnContainerStateChanged(item, associatedItem, ItemState.Recycled); }
internal override double GetItemRelativeOffset(RadVirtualizingDataControlItem item) { switch (this.orientationCache) { case Orientation.Horizontal: return(item.verticalOffsetCache); case Orientation.Vertical: return(item.horizontalOffsetCache); } return(0); }
internal override RadVirtualizingDataControlItem GetTopVisibleContainer() { ////The approach here is to calculate the possible ////index of the topmost item by considering the upper buffer size ////and the average item height. In the ideal case of having equal height ////containers, the index will be calculated exactly. In case of wrong index calculation ////we estimate the direction we have to take in order to find the topmost item and ////interate to it. if (this.owner.realizedItems.Count == 0) { return(null); } if (this.averageItemLength == 0) { return(this.owner.firstItemCache); } double topThresholdAbs = Math.Abs(Math.Max(this.GetItemRelativeOffset(this.owner.firstItemCache), this.topVirtualizationThreshold)); int countOfTopItems = Math.Min((int)(topThresholdAbs / this.averageItemLength), this.owner.realizedItems.Count - 1); RadVirtualizingDataControlItem topElement = this.owner.realizedItems[countOfTopItems]; int deltaFactor = Math.Round(this.GetItemRelativeOffset(topElement), 1) > 0 ? -1 : 1; int realizedItemsCount = this.owner.realizedItems.Count; for (int i = countOfTopItems; i > -1 && i < realizedItemsCount; i += deltaFactor) { topElement = this.owner.realizedItems[i]; if (deltaFactor < 0) { if (Math.Round(this.GetItemRelativeOffset(topElement), 1) <= 0) { return(topElement); } } else { if (Math.Round(this.GetItemRelativeOffset(topElement), 1) == 0) { return(topElement); } if (Math.Round(this.GetItemRelativeOffset(topElement), 1) > 0) { return(topElement.previous != null ? topElement.previous : topElement); } } } return(topElement); }
internal void OnContainerStateChanged(RadVirtualizingDataControlItem container, IDataSourceItem item, ItemState state) { container.UpdateItemState(state); if (state == ItemState.Realized) { container.Attach(this); } else if (state == ItemState.Recycled) { container.Detach(); } this.OnItemStateChanged(item.Value, state); }
internal override void ReorderViewportItemsOnItemRemoved(int removedAt, RadVirtualizingDataControlItem removedContainer) { if (removedAt < this.owner.realizedItems.Count) { IDataSourceItem firstRealized = this.owner.realizedItems[removedAt].associatedDataItem; while (firstRealized != null) { this.slotsRepository.Remove(firstRealized.GetHashCode()); firstRealized = firstRealized.Next; } this.ReorderViewportOnItemsChanged(); } }