/// <summary> /// Constructs an instance of <see cref="VirtualizingCacheBlock{T}"/>. /// </summary> /// <param name="range">The range of the block.</param> /// <param name="items">The items the block holds.</param> public VirtualizingCacheBlock(IndexRange range, T[] items) { _items = items; Range = range; Requests = Enumerable.Empty <VirtualizingCacheBlockRequest <T> >(); }
/// <summary> /// Gets a slice of the block's items based on a given subrange. /// </summary> /// <param name="subrange">The range describing the slice to get.</param> /// <returns>A <see cref="Span{T}"/> holding the slice.</returns> /// <exception cref="ArgumentOutOfRangeException"/> public Span <T> Slice(IndexRange subrange) => Range.Slice(_items, subrange);
/// <summary> /// Transfers to another request with a given effective range. /// </summary> /// <param name="effectiveRange">The effective range of the other request.</param> /// <returns></returns> public VirtualizingCacheBlockRequest <T> Transfer(IndexRange effectiveRange) { return(new VirtualizingCacheBlockRequest <T>(FullRange, effectiveRange, WhenItemsLoaded)); }
/// <summary> /// Applies the change to an array of selected ranges. /// </summary> /// <param name="e">The change.</param> /// <param name="oldSelection">The array of selection.</param> /// <returns>A new array of selected ranges reflecting the change.</returns> public static IndexRange[] ApplyToSelection(this NotifyCollectionChangedEventArgs e, IndexRange[] oldSelection) { if (oldSelection.Length == 0) { return(oldSelection); } var newSelection = new List <IndexRange>(oldSelection); switch (e.Action) { case NotifyCollectionChangedAction.Add: { var searchResult = newSelection.Search(e.NewStartingIndex, IndexRangeSearchApproximation.NearestRight); if (searchResult.IsFound) { var affectedRange = newSelection[searchResult.Index]; if (e.NewStartingIndex > affectedRange.FirstIndex) { newSelection[searchResult.Index] = new IndexRange(affectedRange.FirstIndex, e.NewStartingIndex - 1); newSelection.Insert(searchResult.Index + 1, new IndexRange(e.NewStartingIndex + 1, affectedRange.LastIndex + 1)); newSelection.Shift(1, searchResult.Index + 2); } else { newSelection.Shift(1, searchResult.Index); } } else { newSelection.Shift(1, searchResult.Index); } } break; case NotifyCollectionChangedAction.Remove: { var searchResult = newSelection.Search(e.OldStartingIndex, IndexRangeSearchApproximation.NearestRight); if (searchResult.IsFound) { var affectedRange = newSelection[searchResult.Index]; if (affectedRange.Length > 1) { newSelection[searchResult.Index] = affectedRange.ShrinkLast(1); } else { newSelection.RemoveAt(searchResult.Index); } newSelection.Shift(-1, searchResult.Index + 1); } else { newSelection.Shift(-1, searchResult.Index); if (searchResult.Index > 0) { var nearestLeftRange = newSelection[searchResult.Index - 1]; if (nearestLeftRange.TryUnion(newSelection[searchResult.Index], ref nearestLeftRange)) { newSelection[searchResult.Index - 1] = nearestLeftRange; newSelection.RemoveAt(searchResult.Index); } } } } break; case NotifyCollectionChangedAction.Move: { var searchResult = newSelection.Search(e.OldStartingIndex, IndexRangeSearchApproximation.NearestRight); var previouslySelected = false; if (searchResult.IsFound) { var affectedRange = newSelection[searchResult.Index]; if (affectedRange.Length > 1) { newSelection[searchResult.Index] = affectedRange.ShrinkLast(1); } else { newSelection.RemoveAt(searchResult.Index); } newSelection.Shift(-1, searchResult.Index + 1); previouslySelected = true; } else { newSelection.Shift(-1, searchResult.Index); if (searchResult.Index > 0) { var nearestLeftRange = newSelection[searchResult.Index - 1]; if (nearestLeftRange.TryUnion(newSelection[searchResult.Index], ref nearestLeftRange)) { newSelection[searchResult.Index - 1] = nearestLeftRange; newSelection.RemoveAt(searchResult.Index); } } } searchResult = newSelection.Search(e.NewStartingIndex, IndexRangeSearchApproximation.NearestRight); if (searchResult.IsFound) { var affectedRange = newSelection[searchResult.Index]; if (previouslySelected) { newSelection[searchResult.Index] = affectedRange.ExpandLast(1); newSelection.Shift(1, searchResult.Index + 1); } else { if (e.NewStartingIndex > affectedRange.FirstIndex) { newSelection[searchResult.Index] = new IndexRange(affectedRange.FirstIndex, e.NewStartingIndex - 1); newSelection.Insert(searchResult.Index + 1, new IndexRange(e.NewStartingIndex + 1, affectedRange.LastIndex + 1)); newSelection.Shift(1, searchResult.Index + 2); } else { newSelection.Shift(1, searchResult.Index); } } } else { if (previouslySelected) { var newRange = new IndexRange(e.NewStartingIndex, e.NewStartingIndex); if (searchResult.Index == -1 || searchResult.Index > 0) { var nearestLeftIndex = searchResult.Index == -1 ? newSelection.Count - 1 : searchResult.Index - 1; if (newRange.TryUnion(newSelection[nearestLeftIndex], ref newRange)) { newSelection[nearestLeftIndex] = newRange; newSelection.Shift(1, nearestLeftIndex + 1); } else { newSelection.Insert(nearestLeftIndex + 1, newRange); newSelection.Shift(1, nearestLeftIndex + 2); } } else { newSelection.Insert(searchResult.Index, newRange); newSelection.Shift(1, searchResult.Index + 1); } } else { newSelection.Shift(1, searchResult.Index); } } } break; } return(newSelection.ToArray()); }
/// <summary> /// Constructs a new instance of <see cref="VirtualizingCacheItemsLoadedEvent{T}"/>. /// </summary> /// <param name="range"></param> /// <param name="block"></param> public VirtualizingCacheItemsLoadedEvent(IndexRange range, VirtualizingCacheBlock <T> block) { Range = range; Block = block; }