Example #1
0
        public ItemCacheManager(FetchDataCallbackHandler <T> callback, int batchsize = 50)
        {
            _cacheBlocks       = new List <CacheEntryBlock <T> >();
            _request           = new ItemIndexRangeList();
            _cachedResults     = new ItemIndexRangeList();
            _fetchDataCallback = callback;
            _maxBatchFetchSize = batchsize;

            // set up a timer that is used to delay fetching data so that we can catch up if the list is scrolling fast
            _timer       = new DispatcherTimer();
            _timer.Tick += (sender, args) => { FetchData(); };

            _timer.Interval = new TimeSpan(20 * 10000);
        }
Example #2
0
        /// <summary>
        ///     Updates the desired item range of the cache, discarding items that are not needed, and figuring out which items
        ///     need to be requested. It will then kick off a fetch if required.
        /// </summary>
        /// <param name="ranges">New set of ranges the cache should hold</param>
        public void UpdateRanges(ItemIndexRange[] ranges)
        {
            // Normalize ranges to get a unique set of discontinuous ranges
            ranges = NormalizeRanges(ranges);

            // Fail fast if the ranges haven't changed
            if (!HasRangesChanged(ranges))
            {
                return;
            }

            // To make the cache update easier, we'll create a new set of CacheEntryBlocks
            List <CacheEntryBlock <T> > newCacheBlocks = new List <CacheEntryBlock <T> >();

            foreach (ItemIndexRange range in ranges)
            {
                CacheEntryBlock <T> newBlock = new CacheEntryBlock <T>
                {
                    FirstIndex = range.FirstIndex,
                    Length     = range.Length,
                    Items      = new T[range.Length]
                };
                newCacheBlocks.Add(newBlock);
            }

            // Copy over data to the new cache blocks from the old ones where there is overlap
            int lastTransferred = 0;

            for (int i = 0; i < ranges.Length; i++)
            {
                CacheEntryBlock <T> newBlock = newCacheBlocks[i];
                ItemIndexRange      range    = ranges[i];
                int j = lastTransferred;
                while (j < _cacheBlocks.Count && _cacheBlocks[j].FirstIndex <= ranges[i].LastIndex)
                {
                    ItemIndexRange      overlap, oldEntryRange;
                    ItemIndexRange[]    added, removed;
                    CacheEntryBlock <T> oldBlock = _cacheBlocks[j];
                    oldEntryRange = new ItemIndexRange(oldBlock.FirstIndex, oldBlock.Length);
                    bool hasOverlap = oldEntryRange.DiffRanges(range, out overlap, out removed, out added);
                    if (hasOverlap)
                    {
                        Array.Copy(oldBlock.Items, overlap.FirstIndex - oldBlock.FirstIndex, newBlock.Items, overlap.FirstIndex - range.FirstIndex, (int)overlap.Length);
                    }

                    j++;
                    if (ranges.Length > i + 1 && oldBlock.LastIndex < ranges[i + 1].FirstIndex)
                    {
                        lastTransferred = j;
                    }
                }
            }

            // swap over to the new cache
            _cacheBlocks = newCacheBlocks;

            // figure out what items need to be fetched because we don't have them in the cache
            _request = new ItemIndexRangeList(ranges);
            ItemIndexRangeList newCachedResults = new ItemIndexRangeList();

            // Use the previous knowlege of what we have cached to form the new list
            foreach (ItemIndexRange range in ranges)
            {
                foreach (ItemIndexRange cached in _cachedResults)
                {
                    ItemIndexRange   overlap;
                    ItemIndexRange[] added, removed;
                    bool             hasOverlap = cached.DiffRanges(range, out overlap, out removed, out added);
                    if (hasOverlap)
                    {
                        newCachedResults.Add(overlap);
                    }
                }
            }

            // remove the data we know we have cached from the results
            foreach (ItemIndexRange range in newCachedResults)
            {
                _request.Subtract(range);
            }

            _cachedResults = newCachedResults;

            StartFetchData();
        }