浏览代码

Moved the realized element list outside.

Class was nearly as big as `VirtualizingStackPanel` itself and getting a bit unwieldy.
Steven Kirk 2 年之前
父节点
当前提交
a08f4ac977
共有 2 个文件被更改,包括 450 次插入443 次删除
  1. 448 0
      src/Avalonia.Controls/Utils/RealizedStackElements.cs
  2. 2 443
      src/Avalonia.Controls/VirtualizingStackPanel.cs

+ 448 - 0
src/Avalonia.Controls/Utils/RealizedStackElements.cs

@@ -0,0 +1,448 @@
+using System;
+using System.Collections.Generic;
+
+namespace Avalonia.Controls.Utils
+{
+    /// <summary>
+    /// Stores the realized element state for a virtualizing panel that arranges its children
+    /// in a stack layout, such as <see cref="VirtualizingStackPanel"/>.
+    /// </summary>
+    internal class RealizedStackElements
+    {
+        private int _firstIndex;
+        private List<Control?>? _elements;
+        private List<double>? _sizes;
+        private double _startU;
+        private bool _startUUnstable;
+
+        /// <summary>
+        /// Gets the number of realized elements.
+        /// </summary>
+        public int Count => _elements?.Count ?? 0;
+
+        /// <summary>
+        /// Gets the index of the first realized element, or -1 if no elements are realized.
+        /// </summary>
+        public int FirstIndex => _elements?.Count > 0 ? _firstIndex : -1;
+
+        /// <summary>
+        /// Gets the index of the last realized element, or -1 if no elements are realized.
+        /// </summary>
+        public int LastIndex => _elements?.Count > 0 ? _firstIndex + _elements.Count - 1 : -1;
+
+        /// <summary>
+        /// Gets the elements.
+        /// </summary>
+        public IReadOnlyList<Control?> Elements => _elements ??= new List<Control?>();
+
+        /// <summary>
+        /// Gets the sizes of the elements on the primary axis.
+        /// </summary>
+        public IReadOnlyList<double> SizeU => _sizes ??= new List<double>();
+
+        /// <summary>
+        /// Gets the position of the first element on the primary axis.
+        /// </summary>
+        public double StartU => _startU;
+
+        /// <summary>
+        /// Adds a newly realized element to the collection.
+        /// </summary>
+        /// <param name="index">The index of the element.</param>
+        /// <param name="element">The element.</param>
+        /// <param name="u">The position of the elemnt on the primary axis.</param>
+        /// <param name="sizeU">The size of the element on the primary axis.</param>
+        public void Add(int index, Control element, double u, double sizeU)
+        {
+            if (index < 0)
+                throw new ArgumentOutOfRangeException(nameof(index));
+
+            _elements ??= new List<Control?>();
+            _sizes ??= new List<double>();
+
+            if (Count == 0)
+            {
+                _elements.Add(element);
+                _sizes.Add(sizeU);
+                _startU = u;
+                _firstIndex = index;
+            }
+            else if (index == LastIndex + 1)
+            {
+                _elements.Add(element);
+                _sizes.Add(sizeU);
+            }
+            else if (index == FirstIndex - 1)
+            {
+                --_firstIndex;
+                _elements.Insert(0, element);
+                _sizes.Insert(0, sizeU);
+                _startU = u;
+            }
+            else
+            {
+                throw new NotSupportedException("Can only add items to the beginning or end of realized elements.");
+            }
+        }
+
+        /// <summary>
+        /// Gets the element at the specified index, if realized.
+        /// </summary>
+        /// <param name="index">The index in the source collection of the element to get.</param>
+        /// <returns>The element if realized; otherwise null.</returns>
+        public Control? GetElement(int index)
+        {
+            var i = index - FirstIndex;
+            if (i >= 0 && i < _elements?.Count)
+                return _elements[i];
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the index and start U position of the element at the specified U position.
+        /// </summary>
+        /// <param name="u">The U position.</param>
+        /// <returns>
+        /// A tuple containing:
+        /// - The index of the item at the specified U position, or -1 if the item could not be
+        ///   determined
+        /// - The U position of the start of the item, if determined
+        /// </returns>
+        public (int index, double position) GetIndexAt(double u)
+        {
+            if (_elements is null || _sizes is null || _startU > u || _startUUnstable)
+                return (-1, 0);
+
+            var index = 0;
+            var position = _startU;
+
+            while (index < _elements.Count)
+            {
+                var size = _sizes[index];
+                if (double.IsNaN(size))
+                    break;
+                if (u >= position && u < position + size)
+                    return (index + FirstIndex, position);
+                position += size;
+                ++index;
+            }
+
+            return (-1, 0);
+        }
+
+        /// <summary>
+        /// Gets the element at the specified position on the primary axis, if realized.
+        /// </summary>
+        /// <param name="position">The position.</param>
+        /// <returns>
+        /// A tuple containing the index of the element (or -1 if not found) and the position of the element on the
+        /// primary axis.
+        /// </returns>
+        public (int index, double position) GetElementAt(double position)
+        {
+            if (_sizes is null || position < StartU)
+                return (-1, 0);
+
+            var u = StartU;
+            var i = FirstIndex;
+
+            foreach (var size in _sizes)
+            {
+                var endU = u + size;
+                if (position < endU)
+                    return (i, u);
+                u += size;
+                ++i;
+            }
+
+            return (-1, 0);
+        }
+
+        /// <summary>
+        /// Estimates the average U size of all elements in the source collection based on the
+        /// realized elements.
+        /// </summary>
+        /// <returns>
+        /// The estimated U size of an element, or -1 if not enough information is present to make
+        /// an estimate.
+        /// </returns>
+        public double EstimateElementSizeU()
+        {
+            var total = 0.0;
+            var divisor = 0.0;
+
+            // Start by averaging the size of the elements before the first realized element.
+            if (FirstIndex >= 0 && !_startUUnstable)
+            {
+                total += _startU;
+                divisor += FirstIndex;
+            }
+
+            // Average the size of the realized elements.
+            if (_sizes is not null)
+            {
+                foreach (var size in _sizes)
+                {
+                    if (double.IsNaN(size))
+                        continue;
+                    total += size;
+                    ++divisor;
+                }
+            }
+
+            // We don't have any elements on which to base our estimate.
+            if (divisor == 0 || total == 0)
+                return -1;
+
+            return total / divisor;
+        }
+
+        /// <summary>
+        /// Gets the index of the specified element.
+        /// </summary>
+        /// <param name="element">The element.</param>
+        /// <returns>The index or -1 if the element is not present in the collection.</returns>
+        public int GetIndex(Control element)
+        {
+            return _elements?.IndexOf(element) is int index && index >= 0 ? index + FirstIndex : -1;
+        }
+
+        /// <summary>
+        /// Updates the elements in response to items being inserted into the source collection.
+        /// </summary>
+        /// <param name="index">The index in the source collection of the insert.</param>
+        /// <param name="count">The number of items inserted.</param>
+        /// <param name="updateElementIndex">A method used to update the element indexes.</param>
+        public void ItemsInserted(int index, int count, Action<Control, int, int> updateElementIndex)
+        {
+            if (index < 0)
+                throw new ArgumentOutOfRangeException(nameof(index));
+            if (_elements is null || _elements.Count == 0)
+                return;
+
+            // Get the index within the realized _elements collection.
+            var first = FirstIndex;
+            var realizedIndex = index - first;
+
+            if (realizedIndex < Count)
+            {
+                // The insertion point affects the realized elements. Update the index of the
+                // elements after the insertion point.
+                var elementCount = _elements.Count;
+                var start = Math.Max(realizedIndex, 0);
+                var newIndex = realizedIndex + count;
+
+                for (var i = start; i < elementCount; ++i)
+                {
+                    if (_elements[i] is Control element)
+                        updateElementIndex(element, newIndex - count, newIndex);
+                    ++newIndex;
+                }
+
+                if (realizedIndex < 0)
+                {
+                    // The insertion point was before the first element, update the first index.
+                    _firstIndex += count;
+                }
+                else
+                {
+                    // The insertion point was within the realized elements, insert an empty space
+                    // in _elements and _sizes.
+                    _elements!.InsertMany(realizedIndex, null, count);
+                    _sizes!.InsertMany(realizedIndex, double.NaN, count);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Updates the elements in response to items being removed from the source collection.
+        /// </summary>
+        /// <param name="index">The index in the source collection of the remove.</param>
+        /// <param name="count">The number of items removed.</param>
+        /// <param name="updateElementIndex">A method used to update the element indexes.</param>
+        /// <param name="recycleElement">A method used to recycle elements.</param>
+        public void ItemsRemoved(
+            int index,
+            int count,
+            Action<Control, int, int> updateElementIndex,
+            Action<Control> recycleElement)
+        {
+            if (index < 0)
+                throw new ArgumentOutOfRangeException(nameof(index));
+            if (_elements is null || _elements.Count == 0)
+                return;
+
+            // Get the removal start and end index within the realized _elements collection.
+            var first = FirstIndex;
+            var last = LastIndex;
+            var startIndex = index - first;
+            var endIndex = (index + count) - first;
+
+            if (endIndex < 0)
+            {
+                // The removed range was before the realized elements. Update the first index and
+                // the indexes of the realized elements.
+                _firstIndex -= count;
+                _startUUnstable = true;
+
+                var newIndex = _firstIndex;
+                for (var i = 0; i < _elements.Count; ++i)
+                {
+                    if (_elements[i] is Control element)
+                        updateElementIndex(element, newIndex - count, newIndex);
+                    ++newIndex;
+                }
+            }
+            else if (startIndex < _elements.Count)
+            {
+                // Recycle and remove the affected elements.
+                var start = Math.Max(startIndex, 0);
+                var end = Math.Min(endIndex, _elements.Count);
+
+                for (var i = start; i < end; ++i)
+                {
+                    if (_elements[i] is Control element)
+                        recycleElement(element);
+                }
+
+                _elements.RemoveRange(start, end - start);
+                _sizes!.RemoveRange(start, end - start);
+
+                // If the remove started before and ended within our realized elements, then our new
+                // first index will be the index where the remove started. Mark StartU as unstable
+                // because we can't rely on it now to estimate element heights.
+                if (startIndex <= 0 && end < last)
+                {
+                    _firstIndex = first = index;
+                    _startUUnstable = true;
+                }
+
+                // Update the indexes of the elements after the removed range.
+                end = _elements.Count;
+                var newIndex = first + start;
+                for (var i = start; i < end; ++i)
+                {
+                    if (_elements[i] is Control element)
+                        updateElementIndex(element, newIndex + count, newIndex);
+                    ++newIndex;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Recycles all elements in response to the source collection being reset.
+        /// </summary>
+        /// <param name="recycleElement">A method used to recycle elements.</param>
+        public void ItemsReset(Action<Control> recycleElement)
+        {
+            if (_elements is null || _elements.Count == 0)
+                return;
+
+            foreach (var e in _elements)
+            {
+                if (e is not null)
+                    recycleElement(e);
+            }
+
+            _startU = _firstIndex = 0;
+            _elements?.Clear();
+            _sizes?.Clear();
+
+        }
+
+        /// <summary>
+        /// Recycles elements before a specific index.
+        /// </summary>
+        /// <param name="index">The index in the source collection of new first element.</param>
+        /// <param name="recycleElement">A method used to recycle elements.</param>
+        public void RecycleElementsBefore(int index, Action<Control, int> recycleElement)
+        {
+            if (index <= FirstIndex || _elements is null || _elements.Count == 0)
+                return;
+
+            if (index > LastIndex)
+            {
+                RecycleAllElements(recycleElement);
+            }
+            else
+            {
+                var endIndex = index - FirstIndex;
+
+                for (var i = 0; i < endIndex; ++i)
+                {
+                    if (_elements[i] is Control e)
+                        recycleElement(e, i + FirstIndex);
+                }
+
+                _elements.RemoveRange(0, endIndex);
+                _sizes!.RemoveRange(0, endIndex);
+                _firstIndex = index;
+            }
+        }
+
+        /// <summary>
+        /// Recycles elements after a specific index.
+        /// </summary>
+        /// <param name="index">The index in the source collection of new last element.</param>
+        /// <param name="recycleElement">A method used to recycle elements.</param>
+        public void RecycleElementsAfter(int index, Action<Control, int> recycleElement)
+        {
+            if (index >= LastIndex || _elements is null || _elements.Count == 0)
+                return;
+
+            if (index < FirstIndex)
+            {
+                RecycleAllElements(recycleElement);
+            }
+            else
+            {
+                var startIndex = (index + 1) - FirstIndex;
+                var count = _elements.Count;
+
+                for (var i = startIndex; i < count; ++i)
+                {
+                    if (_elements[i] is Control e)
+                        recycleElement(e, i + FirstIndex);
+                }
+
+                _elements.RemoveRange(startIndex, _elements.Count - startIndex);
+                _sizes!.RemoveRange(startIndex, _sizes.Count - startIndex);
+            }
+        }
+
+        /// <summary>
+        /// Recycles all realized elements.
+        /// </summary>
+        /// <param name="recycleElement">A method used to recycle elements.</param>
+        public void RecycleAllElements(Action<Control, int> recycleElement)
+        {
+            if (_elements is null || _elements.Count == 0)
+                return;
+
+            var i = FirstIndex;
+
+            foreach (var e in _elements)
+            {
+                if (e is not null)
+                    recycleElement(e, i);
+                ++i;
+            }
+
+            _startU = _firstIndex = 0;
+            _elements?.Clear();
+            _sizes?.Clear();
+        }
+
+        /// <summary>
+        /// Resets the element list and prepares it for reuse.
+        /// </summary>
+        public void ResetForReuse()
+        {
+            _startU = _firstIndex = 0;
+            _startUUnstable = false;
+            _elements?.Clear();
+            _sizes?.Clear();
+        }
+    }
+
+}

+ 2 - 443
src/Avalonia.Controls/VirtualizingStackPanel.cs

@@ -65,8 +65,8 @@ namespace Avalonia.Controls
         private bool _isInLayout;
         private bool _isWaitingForViewportUpdate;
         private double _lastEstimatedElementSizeU = 25;
-        private RealizedElementList? _measureElements;
-        private RealizedElementList? _realizedElements;
+        private RealizedStackElements? _measureElements;
+        private RealizedStackElements? _realizedElements;
         private Rect _viewport = s_invalidViewport;
         private Stack<Control>? _recyclePool;
         private Control? _unrealizedFocusedElement;
@@ -853,447 +853,6 @@ namespace Avalonia.Controls
             return snapPoint;
         }
 
-        /// <summary>
-        /// Stores the realized element state for a <see cref="VirtualizingStackPanel"/>.
-        /// </summary>
-        internal class RealizedElementList
-        {
-            private int _firstIndex;
-            private List<Control?>? _elements;
-            private List<double>? _sizes;
-            private double _startU;
-            private bool _startUUnstable;
-
-            /// <summary>
-            /// Gets the number of realized elements.
-            /// </summary>
-            public int Count => _elements?.Count ?? 0;
-
-            /// <summary>
-            /// Gets the index of the first realized element, or -1 if no elements are realized.
-            /// </summary>
-            public int FirstIndex => _elements?.Count > 0 ? _firstIndex : -1;
-
-            /// <summary>
-            /// Gets the index of the last realized element, or -1 if no elements are realized.
-            /// </summary>
-            public int LastIndex => _elements?.Count > 0 ? _firstIndex + _elements.Count - 1 : -1;
-
-            /// <summary>
-            /// Gets the elements.
-            /// </summary>
-            public IReadOnlyList<Control?> Elements => _elements ??= new List<Control?>();
-
-            /// <summary>
-            /// Gets the sizes of the elements on the primary axis.
-            /// </summary>
-            public IReadOnlyList<double> SizeU => _sizes ??= new List<double>();
-
-            /// <summary>
-            /// Gets the position of the first element on the primary axis.
-            /// </summary>
-            public double StartU => _startU;
-
-            /// <summary>
-            /// Adds a newly realized element to the collection.
-            /// </summary>
-            /// <param name="index">The index of the element.</param>
-            /// <param name="element">The element.</param>
-            /// <param name="u">The position of the elemnt on the primary axis.</param>
-            /// <param name="sizeU">The size of the element on the primary axis.</param>
-            public void Add(int index, Control element, double u, double sizeU)
-            {
-                if (index < 0)
-                    throw new ArgumentOutOfRangeException(nameof(index));
-
-                _elements ??= new List<Control?>();
-                _sizes ??= new List<double>();
-
-                if (Count == 0)
-                {
-                    _elements.Add(element);
-                    _sizes.Add(sizeU);
-                    _startU = u;
-                    _firstIndex = index;
-                }
-                else if (index == LastIndex + 1)
-                {
-                    _elements.Add(element);
-                    _sizes.Add(sizeU);
-                }
-                else if (index == FirstIndex - 1)
-                {
-                    --_firstIndex;
-                    _elements.Insert(0, element);
-                    _sizes.Insert(0, sizeU);
-                    _startU = u;
-                }
-                else
-                {
-                    throw new NotSupportedException("Can only add items to the beginning or end of realized elements.");
-                }
-            }
-
-            /// <summary>
-            /// Gets the element at the specified index, if realized.
-            /// </summary>
-            /// <param name="index">The index in the source collection of the element to get.</param>
-            /// <returns>The element if realized; otherwise null.</returns>
-            public Control? GetElement(int index)
-            {
-                var i = index - FirstIndex;
-                if (i >= 0 && i < _elements?.Count)
-                    return _elements[i];
-                return null;
-            }
-
-            /// <summary>
-            /// Gets the index and start U position of the element at the specified U position.
-            /// </summary>
-            /// <param name="u">The U position.</param>
-            /// <returns>
-            /// A tuple containing:
-            /// - The index of the item at the specified U position, or -1 if the item could not be
-            ///   determined
-            /// - The U position of the start of the item, if determined
-            /// </returns>
-            public (int index, double position) GetIndexAt(double u)
-            {
-                if (_elements is null || _sizes is null || _startU > u || _startUUnstable)
-                    return (-1, 0);
-
-                var index = 0;
-                var position = _startU;
-
-                while (index < _elements.Count)
-                {
-                    var size = _sizes[index];
-                    if (double.IsNaN(size))
-                        break;
-                    if (u >= position && u < position + size)
-                        return (index + FirstIndex, position);
-                    position += size;
-                    ++index;
-                }
-
-                return (-1, 0);
-            }
-
-            /// <summary>
-            /// Gets the element at the specified position on the primary axis, if realized.
-            /// </summary>
-            /// <param name="position">The position.</param>
-            /// <returns>
-            /// A tuple containing the index of the element (or -1 if not found) and the position of the element on the
-            /// primary axis.
-            /// </returns>
-            public (int index, double position) GetElementAt(double position)
-            {
-                if (_sizes is null || position < StartU)
-                    return (-1, 0);
-
-                var u = StartU;
-                var i = FirstIndex;
-
-                foreach (var size in _sizes)
-                {
-                    var endU = u + size;
-                    if (position < endU)
-                        return (i, u);
-                    u += size;
-                    ++i;
-                }
-
-                return (-1, 0);
-            }
-
-            /// <summary>
-            /// Estimates the average U size of all elements in the source collection based on the
-            /// realized elements.
-            /// </summary>
-            /// <returns>
-            /// The estimated U size of an element, or -1 if not enough information is present to make
-            /// an estimate.
-            /// </returns>
-            public double EstimateElementSizeU()
-            {
-                var total = 0.0;
-                var divisor = 0.0;
-
-                // Start by averaging the size of the elements before the first realized element.
-                if (FirstIndex >= 0 && !_startUUnstable)
-                {
-                    total += _startU;
-                    divisor += FirstIndex;
-                }
-
-                // Average the size of the realized elements.
-                if (_sizes is not null)
-                {
-                    foreach (var size in _sizes)
-                    {
-                        if (double.IsNaN(size))
-                            continue;
-                        total += size;
-                        ++divisor;
-                    }
-                }
-
-                // We don't have any elements on which to base our estimate.
-                if (divisor == 0 || total == 0)
-                    return -1;
-
-                return total / divisor;
-            }
-
-            /// <summary>
-            /// Gets the index of the specified element.
-            /// </summary>
-            /// <param name="element">The element.</param>
-            /// <returns>The index or -1 if the element is not present in the collection.</returns>
-            public int GetIndex(Control element)
-            {
-                return _elements?.IndexOf(element) is int index && index >= 0 ? index + FirstIndex : -1;
-            }
-
-            /// <summary>
-            /// Updates the elements in response to items being inserted into the source collection.
-            /// </summary>
-            /// <param name="index">The index in the source collection of the insert.</param>
-            /// <param name="count">The number of items inserted.</param>
-            /// <param name="updateElementIndex">A method used to update the element indexes.</param>
-            public void ItemsInserted(int index, int count, Action<Control, int, int> updateElementIndex)
-            {
-                if (index < 0)
-                    throw new ArgumentOutOfRangeException(nameof(index));
-                if (_elements is null || _elements.Count == 0)
-                    return;
-
-                // Get the index within the realized _elements collection.
-                var first = FirstIndex;
-                var realizedIndex = index - first;
-
-                if (realizedIndex < Count)
-                {
-                    // The insertion point affects the realized elements. Update the index of the
-                    // elements after the insertion point.
-                    var elementCount = _elements.Count;
-                    var start = Math.Max(realizedIndex, 0);
-                    var newIndex = realizedIndex + count;
-
-                    for (var i = start; i < elementCount; ++i)
-                    {
-                        if (_elements[i] is Control element)
-                            updateElementIndex(element, newIndex - count, newIndex);
-                        ++newIndex;
-                    }
-
-                    if (realizedIndex < 0)
-                    {
-                        // The insertion point was before the first element, update the first index.
-                        _firstIndex += count;
-                    }
-                    else
-                    {
-                        // The insertion point was within the realized elements, insert an empty space
-                        // in _elements and _sizes.
-                        _elements!.InsertMany(realizedIndex, null, count);
-                        _sizes!.InsertMany(realizedIndex, double.NaN, count);
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Updates the elements in response to items being removed from the source collection.
-            /// </summary>
-            /// <param name="index">The index in the source collection of the remove.</param>
-            /// <param name="count">The number of items removed.</param>
-            /// <param name="updateElementIndex">A method used to update the element indexes.</param>
-            /// <param name="recycleElement">A method used to recycle elements.</param>
-            public void ItemsRemoved(
-                int index,
-                int count,
-                Action<Control, int, int> updateElementIndex,
-                Action<Control> recycleElement)
-            {
-                if (index < 0)
-                    throw new ArgumentOutOfRangeException(nameof(index));
-                if (_elements is null || _elements.Count == 0)
-                    return;
-
-                // Get the removal start and end index within the realized _elements collection.
-                var first = FirstIndex;
-                var last = LastIndex;
-                var startIndex = index - first;
-                var endIndex = (index + count) - first;
-
-                if (endIndex < 0)
-                {
-                    // The removed range was before the realized elements. Update the first index and
-                    // the indexes of the realized elements.
-                    _firstIndex -= count;
-                    _startUUnstable = true;
-
-                    var newIndex = _firstIndex;
-                    for (var i = 0; i < _elements.Count; ++i)
-                    {
-                        if (_elements[i] is Control element)
-                            updateElementIndex(element, newIndex - count, newIndex);
-                        ++newIndex;
-                    }
-                }
-                else if (startIndex < _elements.Count)
-                {
-                    // Recycle and remove the affected elements.
-                    var start = Math.Max(startIndex, 0);
-                    var end = Math.Min(endIndex, _elements.Count);
-
-                    for (var i = start; i < end; ++i)
-                    {
-                        if (_elements[i] is Control element)
-                            recycleElement(element);
-                    }
-
-                    _elements.RemoveRange(start, end - start);
-                    _sizes!.RemoveRange(start, end - start);
-
-                    // If the remove started before and ended within our realized elements, then our new
-                    // first index will be the index where the remove started. Mark StartU as unstable
-                    // because we can't rely on it now to estimate element heights.
-                    if (startIndex <= 0 && end < last)
-                    {
-                        _firstIndex = first = index;
-                        _startUUnstable = true;
-                    }
-
-                    // Update the indexes of the elements after the removed range.
-                    end = _elements.Count;
-                    var newIndex = first + start;
-                    for (var i = start; i < end; ++i)
-                    {
-                        if (_elements[i] is Control element)
-                            updateElementIndex(element, newIndex + count, newIndex);
-                        ++newIndex;
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Recycles all elements in response to the source collection being reset.
-            /// </summary>
-            /// <param name="recycleElement">A method used to recycle elements.</param>
-            public void ItemsReset(Action<Control> recycleElement)
-            {
-                if (_elements is null || _elements.Count == 0)
-                    return;
-
-                foreach (var e in _elements)
-                {
-                    if (e is not null)
-                        recycleElement(e);
-                }
-
-                _startU = _firstIndex = 0;
-                _elements?.Clear();
-                _sizes?.Clear();
-
-            }
-
-            /// <summary>
-            /// Recycles elements before a specific index.
-            /// </summary>
-            /// <param name="index">The index in the source collection of new first element.</param>
-            /// <param name="recycleElement">A method used to recycle elements.</param>
-            public void RecycleElementsBefore(int index, Action<Control, int> recycleElement)
-            {
-                if (index <= FirstIndex || _elements is null || _elements.Count == 0)
-                    return;
-
-                if (index > LastIndex)
-                {
-                    RecycleAllElements(recycleElement);
-                }
-                else
-                {
-                    var endIndex = index - FirstIndex;
-
-                    for (var i = 0; i < endIndex; ++i)
-                    {
-                        if (_elements[i] is Control e)
-                            recycleElement(e, i + FirstIndex);
-                    }
-
-                    _elements.RemoveRange(0, endIndex);
-                    _sizes!.RemoveRange(0, endIndex);
-                    _firstIndex = index;
-                }
-            }
-
-            /// <summary>
-            /// Recycles elements after a specific index.
-            /// </summary>
-            /// <param name="index">The index in the source collection of new last element.</param>
-            /// <param name="recycleElement">A method used to recycle elements.</param>
-            public void RecycleElementsAfter(int index, Action<Control, int> recycleElement)
-            {
-                if (index >= LastIndex || _elements is null || _elements.Count == 0)
-                    return;
-
-                if (index < FirstIndex)
-                {
-                    RecycleAllElements(recycleElement);
-                }
-                else
-                {
-                    var startIndex = (index + 1) - FirstIndex;
-                    var count = _elements.Count;
-
-                    for (var i = startIndex; i < count; ++i)
-                    {
-                        if (_elements[i] is Control e)
-                            recycleElement(e, i + FirstIndex);
-                    }
-
-                    _elements.RemoveRange(startIndex, _elements.Count - startIndex);
-                    _sizes!.RemoveRange(startIndex, _sizes.Count - startIndex);
-                }
-            }
-
-            /// <summary>
-            /// Recycles all realized elements.
-            /// </summary>
-            /// <param name="recycleElement">A method used to recycle elements.</param>
-            public void RecycleAllElements(Action<Control, int> recycleElement)
-            {
-                if (_elements is null || _elements.Count == 0)
-                    return;
-
-                var i = FirstIndex;
-
-                foreach (var e in _elements)
-                {
-                    if (e is not null)
-                        recycleElement(e, i);
-                    ++i;
-                }
-
-                _startU = _firstIndex = 0;
-                _elements?.Clear();
-                _sizes?.Clear();
-            }
-
-            /// <summary>
-            /// Resets the element list and prepares it for reuse.
-            /// </summary>
-            public void ResetForReuse()
-            {
-                _startU = _firstIndex = 0;
-                _startUUnstable = false;
-                _elements?.Clear();
-                _sizes?.Clear();
-            }
-        }
-
         private struct MeasureViewport
         {
             public int firstIndex;