Ejemplo n.º 1
0
        private ExtentInfo GetVerticalExtentInfo(Size viewPortSize)
        {
            if (_itemsControl == null)
            {
                return(new ExtentInfo());
            }

            var extentHeight      = Math.Max(TotalItems * ItemHeight, viewPortSize.Height);
            var maxVerticalOffset = extentHeight;// extentHeight - viewPortSize.Height;
            var verticalOffset    = (StartIndex / (double)TotalItems) * maxVerticalOffset;

            var info = new ExtentInfo
            {
                VirtualCount      = _itemsControl.Items.Count,
                TotalCount        = TotalItems,
                Height            = extentHeight,
                VerticalOffset    = verticalOffset,
                MaxVerticalOffset = maxVerticalOffset
            };

            return(info);
        }
Ejemplo n.º 2
0
        private ItemLayoutInfo GetLayoutInfo(Size availableSize, double itemHeight, ExtentInfo extentInfo)
        {
            if (_itemsControl == null)
            {
                return(new ItemLayoutInfo());
            }

            // we need to ensure that there is one realized item prior to the first visible item, and one after the last visible item,
            // so that keyboard navigation works properly. For example, when focus is on the first visible item, and the user
            // navigates up, the ListBox selects the previous item, and the scrolls that into view - and this triggers the loading of the rest of the items
            // in that row
            var firstVisibleLine      = (int)Math.Floor(_offset.Y / itemHeight);
            var firstRealizedIndex    = Math.Max(firstVisibleLine - 1, 0);
            var firstRealizedItemLeft = firstRealizedIndex * ItemWidth - HorizontalOffset;
            var firstRealizedItemTop  = (firstRealizedIndex) * itemHeight - _offset.Y;
            var firstCompleteLineTop  = (firstVisibleLine == 0 ? firstRealizedItemTop : firstRealizedItemTop + ItemHeight);
            var completeRealizedLines = (int)Math.Ceiling((availableSize.Height - firstCompleteLineTop) / itemHeight);

            var lastRealizedIndex = Math.Min(firstRealizedIndex + completeRealizedLines + 2, _itemsControl.Items.Count - 1);

            return(new ItemLayoutInfo(firstRealizedIndex, firstRealizedItemTop, firstRealizedItemLeft, lastRealizedIndex));
        }
        /// <summary>
        /// Updates the values in the x and y extent lists by the changing aabb values.
        /// </summary>
        private void UpdateExtentValues()
        {
            //NOTE: Comment.. No debug in release
            //Debug.Assert(_xInfoList.Count == _yInfoList.Count);
            for (int i = 0; i < _xInfoList.Count; i++)
            {
                ExtentInfo xInfo = _xInfoList[i];
                ExtentInfo yInfo = _yInfoList[i];
                //NOTE: Comment.. No debug in release
                //Debug.Assert(xInfo.geometry == yInfo.geometry);
                AABB aabb = xInfo.geometry.aabb;

                /*xInfo.min.value = aabb.min.X;
                *  xInfo.max.value = aabb.max.X;
                *  yInfo.min.value = aabb.min.Y;
                *  yInfo.max.value = aabb.max.Y;*/

                xInfo.min.value = aabb.min.X - fTol;
                xInfo.max.value = aabb.max.X + fTol;
                yInfo.min.value = aabb.min.Y - fTol;
                yInfo.max.value = aabb.max.Y + fTol;
            }
        }
Ejemplo n.º 4
0
 private void EnsureScrollOffsetIsWithinConstrains(ExtentInfo extentInfo) {
     if (Orientation == Orientation.Horizontal) {
         _offset.Y = Clamp(_offset.Y, 0, extentInfo.MaxScrollOffset);
     } else {
         _offset.X = Clamp(_offset.X, 0, extentInfo.MaxScrollOffset);
     }
 }
Ejemplo n.º 5
0
        private void CalculateHorizonalScrollInfo()
        {
            _extentInfo = GetExtentInfo(RenderSize);

            UpdateScrollInfo(RenderSize, _extentInfo);
            EnsureScrollOffsetIsWithinConstrains(_extentInfo);

            NotifyHorizonalScroll(_extentInfo);
        }
Ejemplo n.º 6
0
        private void NotifyHorizonalScroll(ExtentInfo extentInfo)
        {
            var startCharacter = Math.Ceiling(_offset.X / CharacterWidth);

            //clamp when required
            if (startCharacter + extentInfo.MaximumChars > TotalCharacters)
                startCharacter = Math.Max(0, TotalCharacters - extentInfo.MaximumChars);
            
            HorizontalScrollChanged?.Invoke(new TextScrollInfo((int)startCharacter, (int)extentInfo.MaximumChars));
        }
Ejemplo n.º 7
0
       protected override Size MeasureOverride(Size availableSize)
        {
            if (_itemsControl == null)
            {
                return new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width,
                    double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);
            }


            _isInMeasure = true;
            _childLayouts.Clear();
            _extentInfo = GetExtentInfo(availableSize);

            EnsureScrollOffsetIsWithinConstrains(_extentInfo);
            var layoutInfo = GetLayoutInfo(availableSize, ItemHeight, _extentInfo);

            RecycleItems(layoutInfo);

            // Determine where the first item is in relation to previously realized items
            var generatorStartPosition = _itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex);

            var visualIndex = 0;
            double widestWidth = 0;
            var currentX = 0;//layoutInfo.FirstRealizedItemLeft;
            var currentY = layoutInfo.FirstRealizedLineTop;
     
            ////1. Calc width, Call back available chars + first char
            //var width = TotalCharacters * CharacterWidth + 22;

            using (_itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true))
            {
                var children = new List<UIElement>();

                for (var itemIndex = layoutInfo.FirstRealizedItemIndex; itemIndex <= layoutInfo.LastRealizedItemIndex; itemIndex++, visualIndex++)
                {
                    bool newlyRealized;

                    var child = (UIElement)_itemsGenerator.GenerateNext(out newlyRealized);
                    if (child == null) continue;

                    children.Add(child);

                    SetVirtualItemIndex(child, itemIndex);

                    if (newlyRealized)
                    {
                        InsertInternalChild(visualIndex, child);
                    }
                    else
                    {
                        // check if item needs to be moved into a new position in the Children collection
                        if (visualIndex < Children.Count)
                        {
                            if (Equals(Children[visualIndex], child)) continue;
                            var childCurrentIndex = Children.IndexOf(child);
                            if (childCurrentIndex >= 0)
                            {
                                RemoveInternalChildRange(childCurrentIndex, 1);
                            }

                            InsertInternalChild(visualIndex, child);
                        }
                        else
                        {
                            // we know that the child can't already be in the children collection
                            // because we've been inserting children in correct visualIndex order,
                            // and this child has a visualIndex greater than the Children.Count
                            AddInternalChild(child);
                        }
                    }
                }

                //part 2: do the measure
                foreach (var child in children)
                {
                    //TODO: Widest = Chars + Additional space = 20
                    //[ideally should scroll from where the text begins]

                    _itemsGenerator.PrepareItemContainer(child);
                    child.Measure(new Size(_viewportSize.Width, ItemHeight));
                    widestWidth = Math.Max(widestWidth, child.DesiredSize.Width); 
                }

            //    Console.WriteLine("Widest={0} Calc={1}", widestWidth, width);

                //part 3: Create the elements
                foreach (var child in children)
                {
                    _childLayouts.Add(child, new Rect(currentX, currentY, Math.Max(_viewportSize.Width, _viewportSize.Width), ItemHeight));
                    currentY += ItemHeight;
                }
            }
            RemoveRedundantChildren();

            UpdateScrollInfo(availableSize, _extentInfo);

            //NotifyHorizonalScroll(_extentInfo);
            _isInMeasure = false;

            return new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);
        }
Ejemplo n.º 8
0
 public Extent(ExtentInfo info, float value, bool isMin)
 {
     Info  = info;
     Value = value;
     IsMin = isMin;
 }
Ejemplo n.º 9
0
        private void UpdateScrollInfo(Size availableSize, ExtentInfo extentInfo)
        {
            _viewportSize = availableSize;
            _extentSize = new Size(availableSize.Width, extentInfo.ExtentHeight);

            InvalidateScrollInfo();
        }
Ejemplo n.º 10
0
 private void EnsureScrollOffsetIsWithinConstrains(ExtentInfo extentInfo)
 {
     _offset.Y = Clamp(_offset.Y, 0, extentInfo.MaxVerticalOffset);
 }
Ejemplo n.º 11
0
 private void UpdateScrollInfo(Size availableSize, ExtentInfo extentInfo)
 {
     _viewportSize = availableSize;
     _extentSize   = Orientation == Orientation.Horizontal ? new Size(availableSize.Width, extentInfo.ExtentSize) : new Size(extentInfo.ExtentSize, availableSize.Height);
     InvalidateScrollInfo();
 }
Ejemplo n.º 12
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (itemsControl == null)
            {
                return(new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width,
                                double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height));
            }

            isInMeasure = true;
            childLayouts.Clear();

            ExtentInfo extentInfo = GetExtentInfo(availableSize);

            EnsureScrollOffsetIsWithinConstrains(extentInfo);

            ItemLayoutInfo layoutInfo = GetLayoutInfo(availableSize, ItemHeight, extentInfo);

            RecycleItems(layoutInfo);

            // Determine where the first item is in relation to previously realized items
            GeneratorPosition generatorStartPosition = itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex);

            var visualIndex = 0;

            double currentX = layoutInfo.FirstRealizedItemLeft;
            double currentY = layoutInfo.FirstRealizedLineTop;

            using (itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true))
            {
                for (int itemIndex = layoutInfo.FirstRealizedItemIndex; itemIndex <= layoutInfo.LastRealizedItemIndex; itemIndex++, visualIndex++)
                {
                    bool newlyRealized;

                    var child = (UIElement)itemsGenerator.GenerateNext(out newlyRealized);
                    SetVirtualItemIndex(child, itemIndex);

                    if (newlyRealized)
                    {
                        InsertInternalChild(visualIndex, child);
                    }
                    else
                    {
                        // check if item needs to be moved into a new position in the Children collection
                        if (visualIndex < Children.Count)
                        {
                            if (!Equals(Children[visualIndex], child))
                            {
                                int childCurrentIndex = Children.IndexOf(child);

                                if (childCurrentIndex >= 0)
                                {
                                    RemoveInternalChildRange(childCurrentIndex, 1);
                                }

                                InsertInternalChild(visualIndex, child);
                            }
                        }
                        else
                        {
                            // we know that the child can't already be in the children collection
                            // because we've been inserting children in correct visualIndex order,
                            // and this child has a visualIndex greater than the Children.Count
                            AddInternalChild(child);
                        }
                    }

                    // only prepare the item once it has been added to the visual tree
                    itemsGenerator.PrepareItemContainer(child);

                    child.Measure(new Size(ItemWidth, ItemHeight));

                    childLayouts.Add(child, new Rect(currentX, currentY, ItemWidth, ItemHeight));

                    if (currentX + ItemWidth * 2 >= availableSize.Width)
                    {
                        // wrap to a new line
                        currentY += ItemHeight;
                        currentX  = 0;
                    }
                    else
                    {
                        currentX += ItemWidth;
                    }
                }
            }

            RemoveRedundantChildren();
            UpdateScrollInfo(availableSize, extentInfo);

            var desiredSize = new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width,
                                       double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);

            isInMeasure = false;

            return(desiredSize);
        }
            /// <summary>
            /// Incrementally inserts the min/max extents into the ExtentList. As it
            /// does so, the method ensures that overlap records, the collisionpair
            /// map, and all other book-keeping is up todate.
            /// </summary>
            /// <param name="ourInfo">The extent info for a give axis</param>
            public void IncrementalInsertExtent(ExtentInfo ourInfo)
            {
                Extent min = ourInfo.min;
                Extent max = ourInfo.max;

                Debug.Assert(min.value < max.value);

                int iMin = InsertIntoSortedList(min);
                int iMax = InsertIntoSortedList(max);

                Geom ourGeom = ourInfo.geometry;

                // As this is a newly inserted extent, we need to update the overlap
                // information.

                // RULE 1: Traverse from min to max. Look for other "min" Extents
                // and when found, add our wrapper/geometry to their list.
                int iCurr = iMin + 1;

                while (iCurr != iMax)
                {
                    if (this[iCurr].isMin)
                    {
                        this[iCurr].info.underConsideration.Add(ourGeom);
                    }
                    iCurr++;
                }

                // RULE 2: From min, traverse to the left until we encounter
                // another "min" extent. If we find one, we add its geometry
                // to our underConsideration list and go to RULE 3, otherwise
                // there is no more work to do and we can exit.
                iCurr = iMin - 1;
                while (iCurr >= 0 && this[iCurr].isMin == false)
                {
                    iCurr--;
                }

                if (iCurr < 0)
                {
                    return;
                }

                List <Geom> ourUnderConsideration = ourInfo.underConsideration;
                Extent      currExtent            = this[iCurr];

                ourUnderConsideration.Add(currExtent.info.geometry);

                // RULE 3: Now that we have found a "min" extent, we take
                // its existing overlap list and copy it into our underConsideration
                // list. All except for ourselves.
                ourUnderConsideration.AddRange(currExtent.info.underConsideration);
                ourUnderConsideration.Remove(ourGeom); // just in case

                /*LinkedListNode<Geom> currGeomNode =
                 *  currExtent.info.underConsideration.First;
                 *
                 * while (currGeomNode != null)
                 * {
                 *  if (currGeomNode.Value != ourGeom)
                 *  {
                 *      ourUnderConsideration.AddLast(new LinkedListNode<Geom>(
                 *          currGeomNode.Value));
                 *  }
                 *  currGeomNode = currGeomNode.Next;
                 * }*/

                // RULE 4: Move from the found extent back toward our "min" extent.
                // Whenever and "max" extent is found, we remove its reference
                // from our extents list.
                while (iCurr != iMin)
                {
                    if (currExtent.isMin == false)
                    {
                        ourUnderConsideration.Remove(currExtent.info.geometry);

                        if (ourInfo.overlaps.Remove(currExtent.info.geometry))
                        {
                            owner.collisionPairs.RemovePair(ourGeom,
                                                            currExtent.info.geometry);
                        }
                    }
                    currExtent = this[++iCurr];
                }
            }
 public Extent(ExtentInfo info, float value, bool isMin)
 {
     this.info  = info;
     this.value = value;
     this.isMin = isMin;
 }
Ejemplo n.º 15
0
 private void UpdateScrollInfo(Size availableSize, ExtentInfo extentInfo) {
     _viewportSize = availableSize;
     _extentSize = Orientation == Orientation.Horizontal ? new Size(availableSize.Width, extentInfo.ExtentSize) : new Size(extentInfo.ExtentSize, availableSize.Height);
     InvalidateScrollInfo();
 }
Ejemplo n.º 16
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (_itemsControl == null)
            {
                return(new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width,
                                double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height));
            }


            _isInMeasure = true;
            _childLayouts.Clear();
            _extentInfo = GetExtentInfo(availableSize);

            EnsureScrollOffsetIsWithinConstrains(_extentInfo);
            var layoutInfo = GetLayoutInfo(availableSize, ItemHeight, _extentInfo);

            RecycleItems(layoutInfo);

            // Determine where the first item is in relation to previously realized items
            var generatorStartPosition = _itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex);

            var    visualIndex = 0;
            double widestWidth = 0;
            var    currentX    = 0;//layoutInfo.FirstRealizedItemLeft;
            var    currentY    = layoutInfo.FirstRealizedLineTop;

            ////1. Calc width, Call back available chars + first char
            //var width = TotalCharacters * CharacterWidth + 22;

            using (_itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true))
            {
                var children = new List <UIElement>();

                for (var itemIndex = layoutInfo.FirstRealizedItemIndex; itemIndex <= layoutInfo.LastRealizedItemIndex; itemIndex++, visualIndex++)
                {
                    bool newlyRealized;

                    var child = (UIElement)_itemsGenerator.GenerateNext(out newlyRealized);
                    if (child == null)
                    {
                        continue;
                    }

                    children.Add(child);

                    SetVirtualItemIndex(child, itemIndex);

                    if (newlyRealized)
                    {
                        InsertInternalChild(visualIndex, child);
                    }
                    else
                    {
                        // check if item needs to be moved into a new position in the Children collection
                        if (visualIndex < Children.Count)
                        {
                            if (Equals(Children[visualIndex], child))
                            {
                                continue;
                            }
                            var childCurrentIndex = Children.IndexOf(child);
                            if (childCurrentIndex >= 0)
                            {
                                RemoveInternalChildRange(childCurrentIndex, 1);
                            }

                            InsertInternalChild(visualIndex, child);
                        }
                        else
                        {
                            // we know that the child can't already be in the children collection
                            // because we've been inserting children in correct visualIndex order,
                            // and this child has a visualIndex greater than the Children.Count
                            AddInternalChild(child);
                        }
                    }
                }

                //part 2: do the measure
                foreach (var child in children)
                {
                    //TODO: Widest = Chars + Additional space = 20
                    //[ideally should scroll from where the text begins]

                    _itemsGenerator.PrepareItemContainer(child);
                    child.Measure(new Size(_viewportSize.Width, ItemHeight));
                    widestWidth = Math.Max(widestWidth, child.DesiredSize.Width);
                }

                //    Console.WriteLine("Widest={0} Calc={1}", widestWidth, width);

                //part 3: Create the elements
                foreach (var child in children)
                {
                    _childLayouts.Add(child, new Rect(currentX, currentY, Math.Max(_viewportSize.Width, _viewportSize.Width), ItemHeight));
                    currentY += ItemHeight;
                }
            }
            RemoveRedundantChildren();

            UpdateScrollInfo(availableSize, _extentInfo);

            //NotifyHorizonalScroll(_extentInfo);
            _isInMeasure = false;

            return(new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height));
        }
Ejemplo n.º 17
0
        private ItemLayoutInfo GetLayoutInfo(Size availableSize, double itemWidth, double itemHeight, ExtentInfo extentInfo)
        {
            if (_itemsControl == null)
            {
                return(new ItemLayoutInfo());
            }

            // we need to ensure that there is one realized item prior to the first visible item, and one after the last visible item,
            // so that keyboard navigation works properly. For example, when focus is on the first visible item, and the user
            // navigates up, the ListBox selects the previous item, and the scrolls that into view - and this triggers the loading of the rest of the items
            // in that row

            if (Orientation == Orientation.Horizontal)
            {
                var firstVisibleLine = (int)Math.Floor(VerticalOffset / itemHeight);

                var firstRealizedIndex    = Math.Max(extentInfo.ItemsPerRow * firstVisibleLine - 1, 0);
                var firstRealizedItemLeft = firstRealizedIndex % extentInfo.ItemsPerRow * itemWidth - HorizontalOffset;
                var firstRealizedItemTop  = Math.Floor((double)firstRealizedIndex / extentInfo.ItemsPerRow) * itemHeight - VerticalOffset;

                var firstCompleteLineTop  = (firstVisibleLine == 0 ? firstRealizedItemTop : firstRealizedItemTop + itemHeight);
                var completeRealizedLines = (int)Math.Ceiling((availableSize.Height - firstCompleteLineTop) / itemHeight);

                var lastRealizedIndex = Math.Min(firstRealizedIndex + completeRealizedLines * extentInfo.ItemsPerRow + 2, _itemsControl.Items.Count - 1);
                return(new ItemLayoutInfo(firstRealizedIndex, firstRealizedItemTop, firstRealizedItemLeft, lastRealizedIndex));
            }
            else
            {
                var firstVisibleColumn = (int)Math.Floor(HorizontalOffset / itemWidth);

                var firstRealizedIndex    = Math.Max(extentInfo.ItemsPerRow * firstVisibleColumn - 1, 0);
                var firstRealizedItemTop  = firstRealizedIndex % extentInfo.ItemsPerRow * itemHeight - VerticalOffset;
                var firstRealizedItemLeft = Math.Floor((double)firstRealizedIndex / extentInfo.ItemsPerRow) * itemWidth - HorizontalOffset;

                var firstCompleteColumnLeft = (firstVisibleColumn == 0 ? firstRealizedItemLeft : firstRealizedItemLeft + itemWidth);
                var completeRealizedColumns = (int)Math.Ceiling((availableSize.Width - firstCompleteColumnLeft) / itemWidth);

                var lastRealizedIndex = Math.Min(firstRealizedIndex + completeRealizedColumns * extentInfo.ItemsPerRow + 2, _itemsControl.Items.Count - 1);
                return(new ItemLayoutInfo(firstRealizedIndex, firstRealizedItemTop, firstRealizedItemLeft, lastRealizedIndex));
            }
        }
Ejemplo n.º 18
0
 private void EnsureScrollOffsetIsWithinConstrains(ExtentInfo extentInfo)
 {
     _offset.Y = Clamp(_offset.Y, 0, extentInfo.MaxVerticalOffset);
 }
Ejemplo n.º 19
0
        private void UpdateScrollInfo(Size availableSize, ExtentInfo extentInfo, double actualWidth)
        {
            _viewportSize = availableSize;
            _extentSize = new Size(actualWidth, extentInfo.Height);

            InvalidateScrollInfo();
        }
Ejemplo n.º 20
0
        private ItemLayoutInfo GetLayoutInfo(Size availableSize, double itemHeight, ExtentInfo extentInfo)
        {
            if (_itemsControl == null)
            {
                return new ItemLayoutInfo();
            }

            // we need to ensure that there is one realized item prior to the first visible item, and one after the last visible item,
            // so that keyboard navigation works properly. For example, when focus is on the first visible item, and the user
            // navigates up, the ListBox selects the previous item, and the scrolls that into view - and this triggers the loading of the rest of the items

            var firstVisibleLine = (int)Math.Floor(VerticalOffset / itemHeight);

            var firstRealizedIndex = Math.Max(extentInfo.ItemsPerLine * firstVisibleLine - 1, 0);
            var firstRealizedItemLeft = firstRealizedIndex % extentInfo.ItemsPerLine * ItemWidth - HorizontalOffset;
            var firstRealizedItemTop = (firstRealizedIndex / extentInfo.ItemsPerLine) * itemHeight - VerticalOffset;

            var firstCompleteLineTop = (firstVisibleLine == 0 ? firstRealizedItemTop : firstRealizedItemTop + ItemHeight);
            var completeRealizedLines = (int)Math.Ceiling((availableSize.Height - firstCompleteLineTop) / itemHeight);

            var lastRealizedIndex = Math.Min(firstRealizedIndex + completeRealizedLines * extentInfo.ItemsPerLine + 2, _itemsControl.Items.Count - 1);

            return new ItemLayoutInfo
            {
                FirstRealizedItemIndex = firstRealizedIndex,
                FirstRealizedItemLeft = firstRealizedItemLeft,
                FirstRealizedLineTop = firstRealizedItemTop,
                LastRealizedItemIndex = lastRealizedIndex,
            };
        }
Ejemplo n.º 21
0
        private ExtentInfo GetVerticalExtentInfo(Size viewPortSize)
        {
            if (_itemsControl == null)
                return new ExtentInfo();
        
            var extentHeight = Math.Max(TotalItems * ItemHeight, viewPortSize.Height);
            var maxVerticalOffset = extentHeight;// extentHeight - viewPortSize.Height;
            var verticalOffset = (StartIndex /(double) TotalItems)*maxVerticalOffset;

            var info = new ExtentInfo
            {
                VirtualCount = _itemsControl.Items.Count,
                TotalCount = TotalItems,
                Height = extentHeight,
                VerticalOffset = verticalOffset,
                MaxVerticalOffset = maxVerticalOffset
            };
            return info;
        }