/// <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));
 }
Example #4
0
        /// <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;
 }