Browse Source

lazy get snapppoints using realized elements in VirtualizingStackPanel

pull/11752/head
Emmanuel Hansen 3 years ago
parent
commit
8f97ae8bbc
  1. 191
      src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs
  2. 103
      src/Avalonia.Controls/VirtualizingStackPanel.cs

191
src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs

@ -0,0 +1,191 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
namespace Avalonia.Controls.Utils
{
internal class VirtualizingSnapPointsList : IReadOnlyList<double>
{
private const int ExtraCount = 2;
private readonly RealizedStackElements _realizedElements;
private readonly Orientation _orientation;
private readonly Orientation _parentOrientation;
private readonly SnapPointsAlignment _snapPointsAlignment;
private readonly double _size;
private readonly int _start = -1;
private readonly int _end;
public VirtualizingSnapPointsList(RealizedStackElements realizedElements, int count, Orientation orientation, Orientation parentOrientation, SnapPointsAlignment snapPointsAlignment, double size)
{
_realizedElements = realizedElements;
_orientation = orientation;
_parentOrientation = parentOrientation;
_snapPointsAlignment = snapPointsAlignment;
_size = size;
if (parentOrientation == orientation)
{
_start = Math.Max(0, _realizedElements.FirstIndex - ExtraCount);
_end = Math.Min(count - 1, _realizedElements.LastIndex + ExtraCount);
}
}
public double this[int index]
{
get
{
if(index < 0 || index >= Count)
throw new ArgumentOutOfRangeException("index");
index += _start;
double snapPoint = 0;
var averageElementSize = _size;
Control? container;
switch (_orientation)
{
case Orientation.Horizontal:
container = _realizedElements.GetElement(index);
if (container != null)
{
switch (_snapPointsAlignment)
{
case SnapPointsAlignment.Near:
snapPoint = container.Bounds.Left;
break;
case SnapPointsAlignment.Center:
snapPoint = container.Bounds.Center.X;
break;
case SnapPointsAlignment.Far:
snapPoint = container.Bounds.Right;
break;
}
}
else
{
var ind = index;
if (index > _realizedElements.LastIndex)
{
ind -= _realizedElements.LastIndex + 1;
}
snapPoint = ind * averageElementSize;
switch (_snapPointsAlignment)
{
case SnapPointsAlignment.Center:
snapPoint += averageElementSize / 2;
break;
case SnapPointsAlignment.Far:
snapPoint += averageElementSize;
break;
}
if (index > _realizedElements.LastIndex)
{
var lastElement = _realizedElements.GetElement(_realizedElements.LastIndex);
if (lastElement != null)
{
snapPoint += lastElement.Bounds.Right;
}
}
}
break;
case Orientation.Vertical:
container = _realizedElements.GetElement(index);
if (container != null)
{
switch (_snapPointsAlignment)
{
case SnapPointsAlignment.Near:
snapPoint = container.Bounds.Top;
break;
case SnapPointsAlignment.Center:
snapPoint = container.Bounds.Center.Y;
break;
case SnapPointsAlignment.Far:
snapPoint = container.Bounds.Bottom;
break;
}
}
else
{
var ind = index;
if(index > _realizedElements.LastIndex)
{
ind -= _realizedElements.LastIndex + 1;
}
snapPoint = ind * averageElementSize;
switch (_snapPointsAlignment)
{
case SnapPointsAlignment.Center:
snapPoint += averageElementSize / 2;
break;
case SnapPointsAlignment.Far:
snapPoint += averageElementSize;
break;
}
if (index > _realizedElements.LastIndex)
{
var lastElement = _realizedElements.GetElement(_realizedElements.LastIndex);
if (lastElement != null)
{
snapPoint += lastElement.Bounds.Bottom;
}
}
}
break;
}
return snapPoint;
}
}
public int Count => _parentOrientation != _orientation ? 0 : _end - _start + 1;
public IEnumerator<double> GetEnumerator()
{
return new VirtualizingEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new VirtualizingEnumerator(this);
}
private class VirtualizingEnumerator : IEnumerator<double>
{
private readonly VirtualizingSnapPointsList _list;
private int _index;
public VirtualizingEnumerator(VirtualizingSnapPointsList list)
{
_list = list;
_index = -1;
}
public double Current => _list[_index];
object IEnumerator.Current => Current;
public void Dispose()
{
_index = 0;
}
public bool MoveNext()
{
_index++;
return _index < _list.Count;
}
public void Reset()
{
_index = -1;
}
}
}
}

103
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -776,107 +776,10 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
public IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment) public IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
{ {
var snapPoints = new List<double>(); if(_realizedElements == null)
var itemCount = ItemsControl?.ItemsSource?.Count() ?? 0; return new List<double>();
switch (orientation)
{
case Orientation.Horizontal:
if (AreHorizontalSnapPointsRegular)
throw new InvalidOperationException();
if (Orientation == Orientation.Horizontal)
{
var averageElementSize = EstimateElementSizeU();
double snapPoint = 0;
for (var i = 0; i < itemCount; i++)
{
var container = ContainerFromIndex(i);
if (container != null)
{
switch (snapPointsAlignment)
{
case SnapPointsAlignment.Near:
snapPoint = container.Bounds.Left;
break;
case SnapPointsAlignment.Center:
snapPoint = container.Bounds.Center.X;
break;
case SnapPointsAlignment.Far:
snapPoint = container.Bounds.Right;
break;
}
}
else
{
if (snapPoint == 0)
{
switch (snapPointsAlignment)
{
case SnapPointsAlignment.Center:
snapPoint = averageElementSize / 2;
break;
case SnapPointsAlignment.Far:
snapPoint = averageElementSize;
break;
}
}
else
snapPoint += averageElementSize;
}
snapPoints.Add(snapPoint);
}
}
break;
case Orientation.Vertical:
if (AreVerticalSnapPointsRegular)
throw new InvalidOperationException();
if (Orientation == Orientation.Vertical)
{
var averageElementSize = EstimateElementSizeU();
double snapPoint = 0;
for (var i = 0; i < itemCount; i++)
{
var container = ContainerFromIndex(i);
if (container != null)
{
switch (snapPointsAlignment)
{
case SnapPointsAlignment.Near:
snapPoint = container.Bounds.Top;
break;
case SnapPointsAlignment.Center:
snapPoint = container.Bounds.Center.Y;
break;
case SnapPointsAlignment.Far:
snapPoint = container.Bounds.Bottom;
break;
}
}
else
{
if (snapPoint == 0)
{
switch (snapPointsAlignment)
{
case SnapPointsAlignment.Center:
snapPoint = averageElementSize / 2;
break;
case SnapPointsAlignment.Far:
snapPoint = averageElementSize;
break;
}
}
else
snapPoint += averageElementSize;
}
snapPoints.Add(snapPoint);
}
}
break;
}
return snapPoints; return new VirtualizingSnapPointsList(_realizedElements, ItemsControl?.ItemsSource?.Count() ?? 0, orientation, Orientation, snapPointsAlignment, EstimateElementSizeU());
} }
/// <inheritdoc/> /// <inheritdoc/>

Loading…
Cancel
Save