Browse Source

Added documentation for item virtualizers.

pull/558/head
Steven Kirk 10 years ago
parent
commit
20847b1960
  1. 86
      src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
  2. 24
      src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
  3. 47
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

86
src/Avalonia.Controls/Presenters/ItemVirtualizer.cs

@ -10,29 +10,88 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls.Presenters namespace Avalonia.Controls.Presenters
{ {
/// <summary>
/// Base class for classes which handle virtualization for an <see cref="ItemsPresenter"/>.
/// </summary>
internal abstract class ItemVirtualizer internal abstract class ItemVirtualizer
{ {
/// <summary>
/// Initializes a new instance of the <see cref="ItemVirtualizer"/> class.
/// </summary>
/// <param name="owner"></param>
public ItemVirtualizer(ItemsPresenter owner) public ItemVirtualizer(ItemsPresenter owner)
{ {
Owner = owner; Owner = owner;
} }
/// <summary>
/// Gets the <see cref="ItemsPresenter"/> which owns the virtualizer.
/// </summary>
public ItemsPresenter Owner { get; } public ItemsPresenter Owner { get; }
/// <summary>
/// Gets the <see cref="IVirtualizingPanel"/> which will host the items.
/// </summary>
public IVirtualizingPanel VirtualizingPanel => Owner.Panel as IVirtualizingPanel; public IVirtualizingPanel VirtualizingPanel => Owner.Panel as IVirtualizingPanel;
/// <summary>
/// Gets the items to display.
/// </summary>
public IEnumerable Items { get; private set; } public IEnumerable Items { get; private set; }
/// <summary>
/// Gets the number of items in <see cref="Items"/>.
/// </summary>
public int ItemCount { get; private set; } public int ItemCount { get; private set; }
public int FirstIndex { get; set; }
public int NextIndex { get; set; } /// <summary>
/// Gets or sets the index of the first item displayed in the panel.
/// </summary>
public int FirstIndex { get; protected set; }
/// <summary>
/// Gets or sets the index of the first item beyond those displayed in the panel.
/// </summary>
public int NextIndex { get; protected set; }
/// <summary>
/// Gets a value indicating whether the items should be scroll horizontally or vertically.
/// </summary>
public bool Vertical => VirtualizingPanel.ScrollDirection == Orientation.Vertical; public bool Vertical => VirtualizingPanel.ScrollDirection == Orientation.Vertical;
/// <summary>
/// Gets a value indicating whether logical scrolling is enabled.
/// </summary>
public abstract bool IsLogicalScrollEnabled { get; } public abstract bool IsLogicalScrollEnabled { get; }
/// <summary>
/// Gets the value of the scroll extent.
/// </summary>
public abstract double ExtentValue { get; } public abstract double ExtentValue { get; }
/// <summary>
/// Gets or sets the value of the current scroll offset.
/// </summary>
public abstract double OffsetValue { get; set; } public abstract double OffsetValue { get; set; }
/// <summary>
/// Gets the value of the scrollable viewport.
/// </summary>
public abstract double ViewportValue { get; } public abstract double ViewportValue { get; }
/// <summary>
/// Gets the <see cref="ExtentValue"/> as a <see cref="Size"/>.
/// </summary>
public Size Extent => Vertical ? new Size(0, ExtentValue) : new Size(ExtentValue, 0); public Size Extent => Vertical ? new Size(0, ExtentValue) : new Size(ExtentValue, 0);
/// <summary>
/// Gets the <see cref="ViewportValue"/> as a <see cref="Size"/>.
/// </summary>
public Size Viewport => Vertical ? new Size(0, ViewportValue) : new Size(ViewportValue, 0); public Size Viewport => Vertical ? new Size(0, ViewportValue) : new Size(ViewportValue, 0);
/// <summary>
/// Gets or sets the <see cref="OffsetValue"/> as a <see cref="Vector"/>.
/// </summary>
public Vector Offset public Vector Offset
{ {
get get
@ -46,6 +105,12 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <summary>
/// Creates an <see cref="ItemVirtualizer"/> based on an item presenter's
/// <see cref="ItemVirtualizationMode"/>.
/// </summary>
/// <param name="owner">The items presenter.</param>
/// <returns>An <see cref="ItemVirtualizer"/>.</returns>
public static ItemVirtualizer Create(ItemsPresenter owner) public static ItemVirtualizer Create(ItemsPresenter owner)
{ {
var virtualizingPanel = owner.Panel as IVirtualizingPanel; var virtualizingPanel = owner.Panel as IVirtualizingPanel;
@ -63,13 +128,30 @@ namespace Avalonia.Controls.Presenters
return new ItemVirtualizerNone(owner); return new ItemVirtualizerNone(owner);
} }
/// <summary>
/// Called by the <see cref="Owner"/> when it carries out an arrange.
/// </summary>
/// <param name="finalSize">The final size passed to the arrange.</param>
public abstract void Arranging(Size finalSize); public abstract void Arranging(Size finalSize);
/// <summary>
/// Called when a request is made to bring an item into view.
/// </summary>
/// <param name="target">The item to bring into view.</param>
/// <param name="targetRect">The rect on the item to bring into view.</param>
/// <returns>True if the request was handled; otherwise false.</returns>
public virtual bool BringIntoView(IVisual target, Rect targetRect) public virtual bool BringIntoView(IVisual target, Rect targetRect)
{ {
return false; return false;
} }
/// <summary>
/// Called when the items for the presenter change, either because
/// <see cref="ItemsPresenterBase.Items"/> has been set, the items collection has been
/// modified, or the panel has been created.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="e">A description of the change.</param>
public virtual void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e) public virtual void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e)
{ {
Items = items; Items = items;

24
src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs

@ -10,6 +10,10 @@ using Avalonia.Controls.Utils;
namespace Avalonia.Controls.Presenters namespace Avalonia.Controls.Presenters
{ {
/// <summary>
/// Represents an item virtualizer for an <see cref="ItemsPresenter"/> that doesn't actually
/// virtualize items - it just creates a container for every item.
/// </summary>
internal class ItemVirtualizerNone : ItemVirtualizer internal class ItemVirtualizerNone : ItemVirtualizer
{ {
public ItemVirtualizerNone(ItemsPresenter owner) public ItemVirtualizerNone(ItemsPresenter owner)
@ -17,29 +21,44 @@ namespace Avalonia.Controls.Presenters
{ {
} }
/// <inheritdoc/>
public override bool IsLogicalScrollEnabled => false; public override bool IsLogicalScrollEnabled => false;
/// <summary>
/// This property should never be accessed because <see cref="IsLogicalScrollEnabled"/> is
/// false.
/// </summary>
public override double ExtentValue public override double ExtentValue
{ {
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
} }
/// <summary>
/// This property should never be accessed because <see cref="IsLogicalScrollEnabled"/> is
/// false.
/// </summary>
public override double OffsetValue public override double OffsetValue
{ {
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }
} }
/// <summary>
/// This property should never be accessed because <see cref="IsLogicalScrollEnabled"/> is
/// false.
/// </summary>
public override double ViewportValue public override double ViewportValue
{ {
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
} }
/// <inheritdoc/>
public override void Arranging(Size finalSize) public override void Arranging(Size finalSize)
{ {
// We don't need to do anything here. // We don't need to do anything here.
} }
/// <inheritdoc/>
public override void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e) public override void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e)
{ {
base.ItemsChanged(items, e); base.ItemsChanged(items, e);
@ -47,7 +66,6 @@ namespace Avalonia.Controls.Presenters
var generator = Owner.ItemContainerGenerator; var generator = Owner.ItemContainerGenerator;
var panel = Owner.Panel; var panel = Owner.Panel;
// TODO: Handle Move and Replace etc.
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
@ -77,7 +95,9 @@ namespace Avalonia.Controls.Presenters
break; break;
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
// TODO: Implement Move in a more efficient manner. // TODO: Handle move in a more efficient manner. At the moment we just
// drop through to Reset to recreate all the containers.
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
RemoveContainers(generator.Clear()); RemoveContainers(generator.Clear());

47
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -10,17 +10,28 @@ using Avalonia.Controls.Utils;
namespace Avalonia.Controls.Presenters namespace Avalonia.Controls.Presenters
{ {
/// <summary>
/// Handles virtualization in an <see cref="ItemsPresenter"/> for
/// <see cref="ItemVirtualizationMode.Simple"/>.
/// </summary>
internal class ItemVirtualizerSimple : ItemVirtualizer internal class ItemVirtualizerSimple : ItemVirtualizer
{ {
/// <summary>
/// Initializes a new instance of the <see cref="ItemVirtualizerSimple"/> class.
/// </summary>
/// <param name="owner"></param>
public ItemVirtualizerSimple(ItemsPresenter owner) public ItemVirtualizerSimple(ItemsPresenter owner)
: base(owner) : base(owner)
{ {
} }
/// <inheritdoc/>
public override bool IsLogicalScrollEnabled => true; public override bool IsLogicalScrollEnabled => true;
/// <inheritdoc/>
public override double ExtentValue => ItemCount; public override double ExtentValue => ItemCount;
/// <inheritdoc/>
public override double OffsetValue public override double OffsetValue
{ {
get get
@ -61,6 +72,7 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <inheritdoc/>
public override double ViewportValue public override double ViewportValue
{ {
get get
@ -71,12 +83,14 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <inheritdoc/>
public override void Arranging(Size finalSize) public override void Arranging(Size finalSize)
{ {
CreateAndRemoveContainers(); CreateAndRemoveContainers();
((ILogicalScrollable)Owner).InvalidateScroll(); ((ILogicalScrollable)Owner).InvalidateScroll();
} }
/// <inheritdoc/>
public override void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e) public override void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e)
{ {
base.ItemsChanged(items, e); base.ItemsChanged(items, e);
@ -123,6 +137,10 @@ namespace Avalonia.Controls.Presenters
((ILogicalScrollable)Owner).InvalidateScroll(); ((ILogicalScrollable)Owner).InvalidateScroll();
} }
/// <summary>
/// Creates and removes containers such that we have at most enough containers to fill
/// the panel.
/// </summary>
private void CreateAndRemoveContainers() private void CreateAndRemoveContainers()
{ {
var generator = Owner.ItemContainerGenerator; var generator = Owner.ItemContainerGenerator;
@ -184,6 +202,14 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <summary>
/// Updates the containers in the panel to make sure they are displaying the correct item
/// based on <see cref="ItemVirtualizer.FirstIndex"/>.
/// </summary>
/// <remarks>
/// This method requires that <see cref="ItemVirtualizer.FirstIndex"/> + the number of
/// materialized containers is not more than <see cref="ItemVirtualizer.ItemCount"/>.
/// </remarks>
private void RecycleContainers() private void RecycleContainers()
{ {
var panel = VirtualizingPanel; var panel = VirtualizingPanel;
@ -208,6 +234,19 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <summary>
/// Recycles containers when a move occurs.
/// </summary>
/// <param name="delta">The delta of the move.</param>
/// <remarks>
/// If the move is less than a page, then this method moves the containers for the items
/// that are still visible to the correct place, and recyles and moves the others. For
/// example: if there are 20 items and 10 containers visible and the user scrolls 5
/// items down, then the bottom 5 containers will be moved to the top and the top 5 will
/// be moved to the bottom and recycled to display the newly visible item. Updates
/// <see cref="ItemVirtualizer.FirstIndex"/> and <see cref="ItemVirtualizer.NextIndex"/>
/// with their new values.
/// </remarks>
private void RecycleContainersForMove(int delta) private void RecycleContainersForMove(int delta)
{ {
var panel = VirtualizingPanel; var panel = VirtualizingPanel;
@ -250,6 +289,9 @@ namespace Avalonia.Controls.Presenters
NextIndex += delta; NextIndex += delta;
} }
/// <summary>
/// Recycles containers due to items being removed.
/// </summary>
private void RecycleContainersOnRemove() private void RecycleContainersOnRemove()
{ {
var panel = VirtualizingPanel; var panel = VirtualizingPanel;
@ -283,6 +325,11 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <summary>
/// Removes the specified number of containers from the end of the panel and updates
/// <see cref="ItemVirtualizer.NextIndex"/>.
/// </summary>
/// <param name="count">The number of containers to remove.</param>
private void RemoveContainers(int count) private void RemoveContainers(int count)
{ {
var index = VirtualizingPanel.Children.Count - count; var index = VirtualizingPanel.Children.Count - count;

Loading…
Cancel
Save