Browse Source

Implement INavigableContainer.

pull/9677/head
Steven Kirk 4 years ago
parent
commit
57b1ba965c
  1. 22
      src/Avalonia.Controls/VirtualizingPanel.cs
  2. 70
      src/Avalonia.Controls/VirtualizingStackPanel.cs

22
src/Avalonia.Controls/VirtualizingPanel.cs

@ -3,13 +3,14 @@ using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls.Utils;
using Avalonia.Input;
namespace Avalonia.Controls
{
/// <summary>
/// Base class for panels that can be used to virtualize items.
/// </summary>
public abstract class VirtualizingPanel : Panel
public abstract class VirtualizingPanel : Panel, INavigableContainer
{
private ItemsControl? _itemsControl;
@ -27,11 +28,19 @@ namespace Avalonia.Controls
}
}
IInputElement? INavigableContainer.GetControl(NavigationDirection direction, IInputElement? from, bool wrap)
{
return GetControl(direction, from, wrap);
}
/// <summary>
/// Scrolls the specified item into view.
/// </summary>
/// <param name="index">The index of the item.</param>
protected internal abstract void ScrollIntoView(int index);
/// <returns>
/// The element with the specified index, or null if the element could not be brought into view.
/// </returns>
protected internal abstract Control? ScrollIntoView(int index);
/// <summary>
/// Returns the container for the item at the specified index.
@ -53,6 +62,15 @@ namespace Avalonia.Controls
/// </returns>
protected internal abstract int IndexFromContainer(Control container);
/// <summary>
/// Gets the next control in the specified direction.
/// </summary>
/// <param name="direction">The movement direction.</param>
/// <param name="from">The control from which movement begins.</param>
/// <param name="wrap">Whether to wrap around when the first or last item is reached.</param>
/// <returns>The control.</returns>
protected abstract IInputElement? GetControl(NavigationDirection direction, IInputElement? from, bool wrap);
/// <summary>
/// Called when the <see cref="ItemsControl"/> that owns the panel changes.
/// </summary>

70
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -3,8 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Xml.Linq;
using Avalonia.Controls.Utils;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Utilities;
using Avalonia.VisualTree;
@ -169,19 +169,79 @@ namespace Avalonia.Controls
InvalidateMeasure();
}
protected override IInputElement? GetControl(NavigationDirection direction, IInputElement? from, bool wrap)
{
var count = (ItemsControl?.Items as IList)?.Count ?? 0;
if (count == 0)
return null;
var horiz = Orientation == Orientation.Horizontal;
var fromIndex = from != null ? Children.IndexOf(from) : -1;
var toIndex = fromIndex;
switch (direction)
{
case NavigationDirection.First:
toIndex = 0;
break;
case NavigationDirection.Last:
toIndex = count - 1;
break;
case NavigationDirection.Next:
++toIndex;
break;
case NavigationDirection.Previous:
--toIndex;
break;
case NavigationDirection.Left:
if (horiz)
--toIndex;
break;
case NavigationDirection.Right:
if (horiz)
++toIndex;
break;
case NavigationDirection.Up:
if (!horiz)
--toIndex;
break;
case NavigationDirection.Down:
if (!horiz)
++toIndex;
break;
default:
return null;
}
if (fromIndex == toIndex)
return from;
if (wrap)
{
if (toIndex < 0)
toIndex = count - 1;
else if (toIndex >= count - 1)
toIndex = 0;
}
return ScrollIntoView(toIndex);
}
protected internal override Control? ContainerFromIndex(int index) => _realizedElements?.GetElement(index);
protected internal override int IndexFromContainer(Control container) => _realizedElements?.GetIndex(container) ?? -1;
protected internal override void ScrollIntoView(int index)
protected internal override Control? ScrollIntoView(int index)
{
var items = ItemsControl?.Items as IList;
if (_isInLayout || items is null || index < 0 || index >= items.Count)
return;
return null;
if (GetRealizedElement(index) is Control element)
{
element.BringIntoView();
return element;
}
else if (this.GetVisualRoot() is ILayoutRoot root)
{
@ -216,9 +276,13 @@ namespace Avalonia.Controls
root.LayoutManager.ExecuteLayoutPass();
_isWaitingForViewportUpdate = false;
var result = _anchorElement;
_anchorElement = null;
_anchorIndex = -1;
return result;
}
return null;
}
internal IReadOnlyList<Control?> GetRealizedElements()

Loading…
Cancel
Save