Browse Source

update to rc1

virtualizeing_wrappanel_rc1
Emmanuel Hansen 3 years ago
parent
commit
1f4cb87ef4
  1. 152
      src/Avalonia.Controls/VirtualizingWrapPanel.cs

152
src/Avalonia.Controls/VirtualizingWrapPanel.cs

@ -54,9 +54,16 @@ namespace Avalonia.Controls
private RealizedWrappedElements? _realizedElements;
private ScrollViewer? _scrollViewer;
private Rect _viewport = s_invalidViewport;
private Stack<Control>? _recyclePool;
private Dictionary<object, Stack<Control>>? _recyclePool;
private Control? _unrealizedFocusedElement;
private int _unrealizedFocusedIndex = -1;
private Control? _focusedElement;
private int _focusedIndex = -1;
private static readonly object s_itemIsItsOwnContainer = new object();
private static readonly AttachedProperty<object?> RecycleKeyProperty =
AvaloniaProperty.RegisterAttached<VirtualizingStackPanel, Control, object?>("RecycleKey");
static VirtualizingWrapPanel()
{
@ -297,9 +304,13 @@ namespace Avalonia.Controls
{
if (index < 0 || index >= Items.Count)
return null;
if (_realizedElements?.GetElement(index) is { } realized)
if (_scrollToIndex == index)
return _scrollToElement;
if (_focusedIndex == index)
return _focusedElement;
if (GetRealizedElement(index) is { } realized)
return realized;
if (Items[index] is Control c && c.GetValue(ItemIsOwnContainerProperty))
if (Items[index] is Control c && c.GetValue(RecycleKeyProperty) == s_itemIsItsOwnContainer)
return c;
return null;
}
@ -653,65 +664,81 @@ namespace Avalonia.Controls
private Control GetOrCreateElement(IReadOnlyList<object?> items, int index)
{
var e = GetRealizedElement(index) ??
GetItemIsOwnContainer(items, index) ??
GetRecycledElement(items, index) ??
CreateElement(items, index);
return e;
Debug.Assert(ItemContainerGenerator is not null);
if ((GetRealizedElement(index) ??
GetRealizedElement(index, ref _focusedIndex, ref _focusedElement) ??
GetRealizedElement(index, ref _scrollToIndex, ref _scrollToElement)) is { } realized)
return realized;
var item = items[index];
var generator = ItemContainerGenerator!;
if (generator.NeedsContainer(item, index, out var recycleKey))
{
return GetRecycledElement(item, index, recycleKey) ??
CreateElement(item, index, recycleKey);
}
else
{
return GetItemAsOwnContainer(item, index);
}
}
private Control GetItemAsOwnContainer(object? item, int index)
{
Debug.Assert(ItemContainerGenerator is not null);
var controlItem = (Control)item!;
var generator = ItemContainerGenerator!;
if (!controlItem.IsSet(RecycleKeyProperty))
{
generator.PrepareItemContainer(controlItem, controlItem, index);
AddInternalChild(controlItem);
controlItem.SetValue(RecycleKeyProperty, s_itemIsItsOwnContainer);
generator.ItemContainerPrepared(controlItem, item, index);
}
controlItem.IsVisible = true;
return controlItem;
}
private Control? GetRealizedElement(int index)
{
if (_scrollToIndex == index)
return _scrollToElement;
return _realizedElements?.GetElement(index);
}
private Control? GetItemIsOwnContainer(IReadOnlyList<object?> items, int index)
private static Control? GetRealizedElement(
int index,
ref int specialIndex,
ref Control? specialElement)
{
var item = items[index];
if (item is Control controlItem)
if (specialIndex == index)
{
var generator = ItemContainerGenerator!;
Debug.Assert(specialElement is not null);
if (controlItem.IsSet(ItemIsOwnContainerProperty))
{
controlItem.IsVisible = true;
return controlItem;
}
else if (generator.IsItemItsOwnContainer(controlItem))
{
generator.PrepareItemContainer(controlItem, controlItem, index);
AddInternalChild(controlItem);
controlItem.SetValue(ItemIsOwnContainerProperty, true);
generator.ItemContainerPrepared(controlItem, item, index);
return controlItem;
}
var result = specialElement;
specialIndex = -1;
specialElement = null;
return result;
}
return null;
}
private Control? GetRecycledElement(IReadOnlyList<object?> items, int index)
private Control? GetRecycledElement(object? item, int index, object? recycleKey)
{
Debug.Assert(ItemContainerGenerator is not null);
var generator = ItemContainerGenerator!;
var item = items[index];
if (recycleKey is null)
return null;
if (_unrealizedFocusedIndex == index && _unrealizedFocusedElement is not null)
{
var element = _unrealizedFocusedElement;
_unrealizedFocusedElement.LostFocus -= OnUnrealizedFocusedElementLostFocus;
_unrealizedFocusedElement = null;
_unrealizedFocusedIndex = -1;
return element;
}
var generator = ItemContainerGenerator!;
if (_recyclePool?.Count > 0)
if (_recyclePool?.TryGetValue(recycleKey, out var recyclePool) == true && recyclePool.Count > 0)
{
var recycled = _recyclePool.Pop();
var recycled = recyclePool.Pop();
recycled.IsVisible = true;
generator.PrepareItemContainer(recycled, item, index);
generator.ItemContainerPrepared(recycled, item, index);
@ -721,14 +748,14 @@ namespace Avalonia.Controls
return null;
}
private Control CreateElement(IReadOnlyList<object?> items, int index)
private Control CreateElement(object? item, int index, object? recycleKey)
{
Debug.Assert(ItemContainerGenerator is not null);
var generator = ItemContainerGenerator!;
var item = items[index];
var container = generator.CreateContainer();
var container = generator.CreateContainer(item, index, recycleKey);
container.SetValue(RecycleKeyProperty, recycleKey);
generator.PrepareItemContainer(container, item, index);
AddInternalChild(container);
generator.ItemContainerPrepared(container, item, index);
@ -742,21 +769,26 @@ namespace Avalonia.Controls
_scrollViewer?.UnregisterAnchorCandidate(element);
if (element.IsSet(ItemIsOwnContainerProperty))
var recycleKey = element.GetValue(RecycleKeyProperty);
if (recycleKey is null)
{
RemoveInternalChild(element);
}
else if (recycleKey == s_itemIsItsOwnContainer)
{
element.IsVisible = false;
}
else if (element.IsKeyboardFocusWithin)
{
_unrealizedFocusedElement = element;
_unrealizedFocusedIndex = index;
_unrealizedFocusedElement.LostFocus += OnUnrealizedFocusedElementLostFocus;
_focusedElement = element;
_focusedIndex = index;
_focusedElement.LostFocus += OnUnrealizedFocusedElementLostFocus;
}
else
{
ItemContainerGenerator!.ClearItemContainer(element);
_recyclePool ??= new();
_recyclePool.Push(element);
PushToRecyclePool(recycleKey, element);
element.IsVisible = false;
}
}
@ -765,19 +797,33 @@ namespace Avalonia.Controls
{
Debug.Assert(ItemContainerGenerator is not null);
if (element.IsSet(ItemIsOwnContainerProperty))
var recycleKey = element.GetValue(RecycleKeyProperty);
if (recycleKey is null || recycleKey == s_itemIsItsOwnContainer)
{
RemoveInternalChild(element);
}
else
{
ItemContainerGenerator!.ClearItemContainer(element);
_recyclePool ??= new();
_recyclePool.Push(element);
PushToRecyclePool(recycleKey, element);
element.IsVisible = false;
}
}
private void PushToRecyclePool(object recycleKey, Control element)
{
_recyclePool ??= new();
if (!_recyclePool.TryGetValue(recycleKey, out var pool))
{
pool = new();
_recyclePool.Add(recycleKey, pool);
}
pool.Push(element);
}
private void UpdateElementIndex(Control element, int oldIndex, int newIndex)
{
Debug.Assert(ItemContainerGenerator is not null);

Loading…
Cancel
Save