Browse Source

Added docs for ItemsRepeater-related classes.

pull/2603/head
Steven Kirk 7 years ago
parent
commit
3a2876f1ef
  1. 3
      src/Avalonia.Controls/Repeaters/ItemTemplateWrapper.cs
  2. 108
      src/Avalonia.Controls/Repeaters/ItemsRepeater.cs
  3. 8
      src/Avalonia.Controls/Repeaters/ItemsRepeaterElementClearingEventArgs.cs
  4. 12
      src/Avalonia.Controls/Repeaters/ItemsRepeaterElementIndexChangedEventArgs.cs
  5. 13
      src/Avalonia.Controls/Repeaters/ItemsRepeaterElementPreparedEventArgs.cs
  6. 49
      src/Avalonia.Controls/Repeaters/ItemsSourceView.cs
  7. 79
      src/Avalonia.Controls/Repeaters/Layout.cs
  8. 14
      src/Avalonia.Controls/Repeaters/LayoutContext.cs
  9. 8
      src/Avalonia.Controls/Repeaters/NonVirtualizingLayout.cs
  10. 27
      src/Avalonia.Controls/Repeaters/StackLayout.cs
  11. 3
      src/Avalonia.Controls/Repeaters/StackLayoutState.cs
  12. 124
      src/Avalonia.Controls/Repeaters/UniformGridLayout.cs
  13. 3
      src/Avalonia.Controls/Repeaters/UniformGridLayoutState.cs
  14. 68
      src/Avalonia.Controls/Repeaters/VirtualizingLayout.cs

3
src/Avalonia.Controls/Repeaters/ItemTemplateWrapper.cs

@ -3,9 +3,6 @@
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Controls.Templates;
namespace Avalonia.Controls.Repeaters

108
src/Avalonia.Controls/Repeaters/ItemsRepeater.cs

@ -11,18 +11,42 @@ using Avalonia.Input;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents a data-driven collection control that incorporates a flexible layout system,
/// custom views, and virtualization.
/// </summary>
public class ItemsRepeater : Panel
{
/// <summary>
/// Defines the <see cref="HorizontalCacheLength"/> property.
/// </summary>
public static readonly AvaloniaProperty<double> HorizontalCacheLengthProperty =
AvaloniaProperty.Register<ItemsRepeater, double>(nameof(HorizontalCacheLength), 2.0);
/// <summary>
/// Defines the <see cref="ItemTemplate"/> property.
/// </summary>
public static readonly StyledProperty<IDataTemplate> ItemTemplateProperty =
ItemsControl.ItemTemplateProperty.AddOwner<ItemsRepeater>();
/// <summary>
/// Defines the <see cref="Items"/> property.
/// </summary>
public static readonly DirectProperty<ItemsRepeater, IEnumerable> ItemsProperty =
ItemsControl.ItemsProperty.AddOwner<ItemsRepeater>(o => o.Items, (o, v) => o.Items = v);
/// <summary>
/// Defines the <see cref="Layout"/> property.
/// </summary>
public static readonly AvaloniaProperty<Layout> LayoutProperty =
AvaloniaProperty.Register<ItemsRepeater, Layout>(nameof(Layout), new StackLayout());
/// <summary>
/// Defines the <see cref="VerticalCacheLength"/> property.
/// </summary>
public static readonly AvaloniaProperty<double> VerticalCacheLengthProperty =
AvaloniaProperty.Register<ItemsRepeater, double>(nameof(VerticalCacheLength), 2.0);
private static readonly AttachedProperty<VirtualizationInfo> VirtualizationInfoProperty =
AvaloniaProperty.RegisterAttached<ItemsRepeater, IControl, VirtualizationInfo>("VirtualizationInfo");
@ -40,6 +64,9 @@ namespace Avalonia.Controls.Repeaters
private ItemsRepeaterElementClearingEventArgs _elementClearingArgs;
private ItemsRepeaterElementIndexChangedEventArgs _elementIndexChangedArgs;
/// <summary>
/// Initializes a new instance of the <see cref="ItemsRepeater"/> class.
/// </summary>
public ItemsRepeater()
{
_viewManager = new ViewManager(this);
@ -53,36 +80,61 @@ namespace Avalonia.Controls.Repeaters
ClipToBoundsProperty.OverrideDefaultValue<ItemsRepeater>(true);
}
/// <summary>
/// Gets or sets the layout used to size and position elements in the ItemsRepeater.
/// </summary>
/// <value>
/// The layout used to size and position elements. The default is a StackLayout with
/// vertical orientation.
/// </value>
public Layout Layout
{
get => GetValue(LayoutProperty);
set => SetValue(LayoutProperty, value);
}
/// <summary>
/// Gets or sets an object source used to generate the content of the ItemsRepeater.
/// </summary>
public IEnumerable Items
{
get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value);
}
/// <summary>
/// Gets or sets the template used to display each item.
/// </summary>
public IDataTemplate ItemTemplate
{
get => GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
/// <summary>
/// Gets or sets a value that indicates the size of the buffer used to realize items when
/// panning or scrolling horizontally.
/// </summary>
public double HorizontalCacheLength
{
get => GetValue(HorizontalCacheLengthProperty);
set => SetValue(HorizontalCacheLengthProperty, value);
}
/// <summary>
/// Gets or sets a value that indicates the size of the buffer used to realize items when
/// panning or scrolling vertically.
/// </summary>
public double VerticalCacheLength
{
get => GetValue(VerticalCacheLengthProperty);
set => SetValue(VerticalCacheLengthProperty, value);
}
/// <summary>
/// Gets a standardized view of the supported interactions between a given Items object and
/// the ItemsRepeater control and its associated components.
/// </summary>
public ItemsSourceView ItemsSourceView { get; private set; }
internal ItemTemplateWrapper ItemTemplateShim { get; set; }
@ -107,19 +159,69 @@ namespace Avalonia.Controls.Repeaters
}
}
/// <summary>
/// Occurs each time an element is cleared and made available to be re-used.
/// </summary>
/// <remarks>
/// This event is raised immediately each time an element is cleared, such as when it falls
/// outside the range of realized items. Elements are cleared when they become available
/// for re-use.
/// </remarks>
public event EventHandler<ItemsRepeaterElementClearingEventArgs> ElementClearing;
/// <summary>
/// Occurs for each realized <see cref="IControl"/> when the index for the item it
/// represents has changed.
/// </summary>
/// <remarks>
/// When you use ItemsRepeater to build a more complex control that supports specific
/// interactions on the child elements (such as selection or click), it is useful to be
/// able to keep an up-to-date identifier for the backing data item.
///
/// This event is raised for each realized IControl where the index for the item it
/// represents has changed. For example, when another item is added or removed in the data
/// source, the index for items that come after in the ordering will be impacted.
/// </remarks>
public event EventHandler<ItemsRepeaterElementIndexChangedEventArgs> ElementIndexChanged;
/// <summary>
/// Occurs each time an element is prepared for use.
/// </summary>
/// <remarks>
/// The prepared element might be newly created or an existing element that is being re-
/// used.
/// </remarks>
public event EventHandler<ItemsRepeaterElementPreparedEventArgs> ElementPrepared;
/// <summary>
/// Retrieves the index of the item from the data source that corresponds to the specified
/// <see cref="IControl"/>.
/// </summary>
/// <param name="element">
/// The element that corresponds to the item to get the index of.
/// </param>
/// <returns>
/// The index of the item from the data source that corresponds to the specified UIElement,
/// or -1 if the element is not supported.
/// </returns>
public int GetElementIndex(IControl element) => GetElementIndexImpl(element);
/// <summary>
/// Retrieves the realized UIElement that corresponds to the item at the specified index in
/// the data source.
/// </summary>
/// <param name="index">The index of the item.</param>
/// <returns>
/// he UIElement that corresponds to the item at the specified index if the item is
/// realized, or null if the item is not realized.
/// </returns>
public IControl TryGetElement(int index) => GetElementFromIndexImpl(index);
public void PinElement(IControl element) => _viewManager.UpdatePin(element, true);
internal void PinElement(IControl element) => _viewManager.UpdatePin(element, true);
public void UnpinElement(IControl element) => _viewManager.UpdatePin(element, false);
internal void UnpinElement(IControl element) => _viewManager.UpdatePin(element, false);
public IControl GetOrCreateElement(int index) => GetOrCreateElementImpl(index);
internal IControl GetOrCreateElement(int index) => GetOrCreateElementImpl(index);
internal static VirtualizationInfo TryGetVirtualizationInfo(IControl element)
{

8
src/Avalonia.Controls/Repeaters/ItemsRepeaterElementClearingEventArgs.cs

@ -7,10 +7,18 @@ using System;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Provides data for the <see cref="ItemsRepeater.ElementClearing"/> event.
/// </summary>
public class ItemsRepeaterElementClearingEventArgs : EventArgs
{
internal ItemsRepeaterElementClearingEventArgs(IControl element) => Element = element;
/// <summary>
/// Gets the element that is being cleared for re-use.
/// </summary>
public IControl Element { get; private set; }
internal void Update(IControl element) => Element = element;
}
}

12
src/Avalonia.Controls/Repeaters/ItemsRepeaterElementIndexChangedEventArgs.cs

@ -7,6 +7,9 @@ using System;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Provides data for the <see cref="ItemsRepeater.ElementIndexChanged"/> event.
/// </summary>
public class ItemsRepeaterElementIndexChangedEventArgs : EventArgs
{
internal ItemsRepeaterElementIndexChangedEventArgs(IControl element, int newIndex, int oldIndex)
@ -16,10 +19,19 @@ namespace Avalonia.Controls.Repeaters
OldIndex = oldIndex;
}
/// <summary>
/// Get the element for which the index changed.
/// </summary>
public IControl Element { get; private set; }
/// <summary>
/// Gets the index of the element after the change.
/// </summary>
public int NewIndex { get; private set; }
/// <summary>
/// Gets the index of the element before the change.
/// </summary>
public int OldIndex { get; private set; }
internal void Update(IControl element, int newIndex, int oldIndex)

13
src/Avalonia.Controls/Repeaters/ItemsRepeaterElementPreparedEventArgs.cs

@ -3,12 +3,11 @@
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Provides data for the <see cref="ItemsRepeater.ElementPrepared"/> event.
/// </summary>
public class ItemsRepeaterElementPreparedEventArgs
{
internal ItemsRepeaterElementPreparedEventArgs(IControl element, int index)
@ -17,8 +16,14 @@ namespace Avalonia.Controls.Repeaters
Index = index;
}
/// <summary>
/// Gets the prepared element.
/// </summary>
public IControl Element { get; private set; }
/// <summary>
/// Gets the index of the item the element was prepared for.
/// </summary>
public int Index { get; private set; }
internal void Update(IControl element, int index)

49
src/Avalonia.Controls/Repeaters/ItemsSourceView.cs

@ -11,12 +11,26 @@ using System.Linq;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents a standardized view of the supported interactions between a given ItemsSource
/// object and an <see cref="ItemsRepeater"/> control.
/// </summary>
/// <remarks>
/// Components written to work with ItemsRepeater should consume the
/// <see cref="ItemsRepeater.Items"/> via ItemsSourceView since this provides a normalized
/// view of the Items. That way, each component does not need to know if the source is an
/// IEnumerable, an IList, or something else.
/// </remarks>
public class ItemsSourceView : INotifyCollectionChanged, IDisposable
{
private readonly IList _inner;
private INotifyCollectionChanged _notifyCollectionChanged;
private int _cachedSize = -1;
/// <summary>
/// Initializes a new instance of the ItemsSourceView class for the specified data source.
/// </summary>
/// <param name="source">The data source.</param>
public ItemsSourceView(IEnumerable source)
{
Contract.Requires<ArgumentNullException>(source != null);
@ -35,6 +49,9 @@ namespace Avalonia.Controls.Repeaters
ListenToCollectionChanges();
}
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
public int Count
{
get
@ -48,11 +65,20 @@ namespace Avalonia.Controls.Repeaters
}
}
/// <summary>
/// Gets a value that indicates whether the items source can provide a unique key for each item.
/// </summary>
/// <remarks>
/// TODO: Not yet implemented in Avalonia.
/// </remarks>
public bool HasKeyIndexMapping => false;
/// <summary>
/// Occurs when the collection has changed to indicate the reason for the change and which items changed.
/// </summary>
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <inheritdoc/>
public void Dispose()
{
if (_notifyCollectionChanged != null)
@ -61,13 +87,34 @@ namespace Avalonia.Controls.Repeaters
}
}
/// <summary>
/// Retrieves the item at the specified index.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>the item.</returns>
public object GetAt(int index) => _inner[index];
/// <summary>
/// Retrieves the index of the item that has the specified unique identifier (key).
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The key</returns>
/// <remarks>
/// TODO: Not yet implemented in Avalonia.
/// </remarks>
public string KeyFromIndex(int index)
{
throw new NotImplementedException();
}
/// <summary>
/// Retrieves the unique identifier (key) for the item at the specified index.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>The index.</returns>
/// <remarks>
/// TODO: Not yet implemented in Avalonia.
/// </remarks>
public int IndexFromKey(string key)
{
throw new NotImplementedException();

79
src/Avalonia.Controls/Repeaters/Layout.cs

@ -7,23 +7,100 @@ using System;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the base class for an object that sizes and arranges child elements for a host.
/// </summary>
public abstract class Layout : AvaloniaObject
{
public string LayoutId { get; set; }
internal string LayoutId { get; set; }
/// <summary>
/// Occurs when the measurement state (layout) has been invalidated.
/// </summary>
public event EventHandler MeasureInvalidated;
/// <summary>
/// Occurs when the arrange state (layout) has been invalidated.
/// </summary>
public event EventHandler ArrangeInvalidated;
/// <summary>
/// Initializes any per-container state the layout requires when it is attached to an
/// <see cref="IControl"/> container.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <remarks>
/// Container elements that support attached layouts should call this method when a layout
/// instance is first assigned. The container is expected to give the attached layout
/// instance a way to store and retrieve any per-container state by way of the provided
/// context. It is also the responsibility of the container to not reuse the context, or
/// otherwise expose the state from one layout to another.
///
/// When an attached layout is removed the container should release any reference to the
/// layout state it stored.
///
/// Override <see cref="NonVirtualizingLayout.InitializeForContextCore"/> or
/// <see cref="VirtualizingLayout.InitializeForContextCore"/> to provide the behavior for
/// this method in a derived class.
/// </remarks>
public abstract void InitializeForContext(LayoutContext context);
/// <summary>
/// Removes any state the layout previously stored on the IControl container.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
public abstract void UninitializeForContext(LayoutContext context);
/// <summary>
/// Suggests a DesiredSize for a container element. A container element that supports
/// attached layouts should call this method from their own MeasureOverride implementations
/// to form a recursive layout update. The attached layout is expected to call the Measure
/// for each of the container’s IControl children.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <param name="availableSize">
/// The available space that a container can allocate to a child object. A child object can
/// request a larger space than what is available; the provided size might be accommodated
/// if scrolling or other resize behavior is possible in that particular container.
/// </param>
/// <returns></returns>
public abstract Size Measure(LayoutContext context, Size availableSize);
/// <summary>
/// Positions child elements and determines a size for a container UIElement. Container
/// elements that support attached layouts should call this method from their layout
/// override implementations to form a recursive layout update.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <param name="finalSize">
/// The final size that the container computes for the child in layout.
/// </param>
/// <returns>The actual size that is used after the element is arranged in layout.</returns>
public abstract Size Arrange(LayoutContext context, Size finalSize);
/// <summary>
/// Invalidates the measurement state (layout) for all IControl containers that reference
/// this layout.
/// </summary>
protected void InvalidateMeasure() => MeasureInvalidated?.Invoke(this, EventArgs.Empty);
/// <summary>
/// Invalidates the arrange state (layout) for all UIElement containers that reference this
/// layout. After the invalidation, the UIElement will have its layout updated, which
/// occurs asynchronously.
/// </summary>
protected void InvalidateArrange() => ArrangeInvalidated?.Invoke(this, EventArgs.Empty);
}
}

14
src/Avalonia.Controls/Repeaters/LayoutContext.cs

@ -3,16 +3,22 @@
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the base class for an object that facilitates communication between an attached
/// layout and its host container.
/// </summary>
public class LayoutContext : AvaloniaObject
{
/// <summary>
/// Gets or sets an object that represents the state of a layout.
/// </summary>
public object LayoutState { get; set; }
/// <summary>
/// Implements the behavior of <see cref="LayoutState"/> in a derived or custom LayoutContext.
/// </summary>
protected virtual object LayoutStateCore { get; set; }
}
}

8
src/Avalonia.Controls/Repeaters/NonVirtualizingLayout.cs

@ -3,12 +3,12 @@
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the base class for an object that sizes and arranges child elements for a host
/// and and does not support virtualization.
/// </summary>
public abstract class NonVirtualizingLayout : Layout
{
}

27
src/Avalonia.Controls/Repeaters/StackLayout.cs

@ -8,34 +8,57 @@ using System.Collections.Specialized;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Arranges elements into a single line (with spacing) that can be oriented horizontally or vertically.
/// </summary>
public class StackLayout : VirtualizingLayout, IFlowLayoutAlgorithmDelegates
{
/// <summary>
/// Defines the <see cref="Orientation"/> property.
/// </summary>
public static readonly StyledProperty<Orientation> OrientationProperty =
StackPanel.OrientationProperty.AddOwner<StackLayout>();
/// <summary>
/// Defines the <see cref="Spacing"/> property.
/// </summary>
public static readonly StyledProperty<double> SpacingProperty =
StackPanel.SpacingProperty.AddOwner<StackLayout>();
private readonly OrientationBasedMeasures _orientation = new OrientationBasedMeasures();
/// <summary>
/// Initializes a new instance of the StackLayout class.
/// </summary>
public StackLayout()
{
LayoutId = "StackLayout";
}
/// <summary>
/// Gets or sets the axis along which items are laid out.
/// </summary>
/// <value>
/// One of the enumeration values that specifies the axis along which items are laid out.
/// The default is Vertical.
/// </value>
public Orientation Orientation
{
get => GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
/// <summary>
/// Gets or sets a uniform distance (in pixels) between stacked items. It is applied in the
/// direction of the StackLayout's Orientation.
/// </summary>
public double Spacing
{
get => GetValue(SpacingProperty);
set => SetValue(SpacingProperty, value);
}
public Rect GetExtent(
internal Rect GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
IControl firstRealized,
@ -73,7 +96,7 @@ namespace Avalonia.Controls.Repeaters
return extent;
}
public void OnElementMeasured(
internal void OnElementMeasured(
IControl element,
int index,
Size availableSize,

3
src/Avalonia.Controls/Repeaters/StackLayoutState.cs

@ -9,6 +9,9 @@ using System.Linq;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the state of a StackLayout.
/// </summary>
public class StackLayoutState
{
private const int BufferSize = 100;

124
src/Avalonia.Controls/Repeaters/UniformGridLayout.cs

@ -8,43 +8,111 @@ using System.Collections.Specialized;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Defines constants that specify how items are aligned on the non-scrolling or non-virtualizing axis.
/// </summary>
public enum UniformGridLayoutItemsJustification
{
/// <summary>
/// Items are aligned with the start of the row or column, with extra space at the end.
/// Spacing between items does not change.
/// </summary>
Start = 0,
/// <summary>
/// Items are aligned in the center of the row or column, with extra space at the start and
/// end. Spacing between items does not change.
/// </summary>
Center = 1,
/// <summary>
/// Items are aligned with the end of the row or column, with extra space at the start.
/// Spacing between items does not change.
/// </summary>
End = 2,
/// <summary>
/// Items are aligned so that extra space is added evenly before and after each item.
/// </summary>
SpaceAround = 3,
/// <summary>
/// Items are aligned so that extra space is added evenly between adjacent items. No space
/// is added at the start or end.
/// </summary>
SpaceBetween = 4,
SpaceEvenly = 5,
};
/// <summary>
/// Defines constants that specify how items are sized to fill the available space.
/// </summary>
public enum UniformGridLayoutItemsStretch
{
/// <summary>
/// The item retains its natural size. Use of extra space is determined by the
/// <see cref="UniformGridLayout.ItemsJustification"/> property.
/// </summary>
None = 0,
/// <summary>
/// The item is sized to fill the available space in the non-scrolling direction. Item size
/// in the scrolling direction is not changed.
/// </summary>
Fill = 1,
/// <summary>
/// The item is sized to both fill the available space in the non-scrolling direction and
/// maintain its aspect ratio.
/// </summary>
Uniform = 2,
};
/// <summary>
/// Positions elements sequentially from left to right or top to bottom in a wrapping layout.
/// </summary>
public class UniformGridLayout : VirtualizingLayout, IFlowLayoutAlgorithmDelegates
{
/// <summary>
/// Defines the <see cref="ItemsJustification"/> property.
/// </summary>
public static readonly StyledProperty<UniformGridLayoutItemsJustification> ItemsJustificationProperty =
AvaloniaProperty.Register<UniformGridLayout, UniformGridLayoutItemsJustification>(nameof(ItemsJustification));
/// <summary>
/// Defines the <see cref="ItemsStretch"/> property.
/// </summary>
public static readonly StyledProperty<UniformGridLayoutItemsStretch> ItemsStretchProperty =
AvaloniaProperty.Register<UniformGridLayout, UniformGridLayoutItemsStretch>(nameof(ItemsStretch));
/// <summary>
/// Defines the <see cref="MinColumnSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> MinColumnSpacingProperty =
AvaloniaProperty.Register<UniformGridLayout, double>(nameof(MinColumnSpacing));
/// <summary>
/// Defines the <see cref="MinItemHeight"/> property.
/// </summary>
public static readonly StyledProperty<double> MinItemHeightProperty =
AvaloniaProperty.Register<UniformGridLayout, double>(nameof(MinItemHeight));
/// <summary>
/// Defines the <see cref="MinItemWidth"/> property.
/// </summary>
public static readonly StyledProperty<double> MinItemWidthProperty =
AvaloniaProperty.Register<UniformGridLayout, double>(nameof(MinItemWidth));
/// <summary>
/// Defines the <see cref="MinRowSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> MinRowSpacingProperty =
AvaloniaProperty.Register<UniformGridLayout, double>(nameof(MinRowSpacing));
/// <summary>
/// Defines the <see cref="Orientation"/> property.
/// </summary>
public static readonly StyledProperty<Orientation> OrientationProperty =
StackPanel.OrientationProperty.AddOwner<StackLayout>();
@ -56,6 +124,9 @@ namespace Avalonia.Controls.Repeaters
private UniformGridLayoutItemsJustification _itemsJustification;
private UniformGridLayoutItemsStretch _itemsStretch;
/// <summary>
/// Initializes a new instance of the <see cref="UniformGridLayout"/> class.
/// </summary>
public UniformGridLayout()
{
LayoutId = "UniformGridLayout";
@ -66,42 +137,95 @@ namespace Avalonia.Controls.Repeaters
OrientationProperty.OverrideDefaultValue<UniformGridLayout>(Orientation.Horizontal);
}
/// <summary>
/// Gets or sets a value that indicates how items are aligned on the non-scrolling or non-
/// virtualizing axis.
/// </summary>
/// <value>
/// An enumeration value that indicates how items are aligned. The default is Start.
/// </value>
public UniformGridLayoutItemsJustification ItemsJustification
{
get => GetValue(ItemsJustificationProperty);
set => SetValue(ItemsJustificationProperty, value);
}
/// <summary>
/// Gets or sets a value that indicates how items are sized to fill the available space.
/// </summary>
/// <value>
/// An enumeration value that indicates how items are sized to fill the available space.
/// The default is None.
/// </value>
/// <remarks>
/// This property enables adaptive layout behavior where the items are sized to fill the
/// available space along the non-scrolling axis, and optionally maintain their aspect ratio.
/// </remarks>
public UniformGridLayoutItemsStretch ItemsStretch
{
get => GetValue(ItemsStretchProperty);
set => SetValue(ItemsStretchProperty, value);
}
/// <summary>
/// Gets or sets the minimum space between items on the horizontal axis.
/// </summary>
/// <remarks>
/// The spacing may exceed this minimum value when <see cref="ItemsJustification"/> is set
/// to SpaceEvenly, SpaceAround, or SpaceBetween.
/// </remarks>
public double MinColumnSpacing
{
get => GetValue(MinColumnSpacingProperty);
set => SetValue(MinColumnSpacingProperty, value);
}
/// <summary>
/// Gets or sets the minimum height of each item.
/// </summary>
/// <value>
/// The minimum height (in pixels) of each item. The default is NaN, in which case the
/// height of the first item is used as the minimum.
/// </value>
public double MinItemHeight
{
get => GetValue(MinItemHeightProperty);
set => SetValue(MinItemHeightProperty, value);
}
/// <summary>
/// Gets or sets the minimum width of each item.
/// </summary>
/// <value>
/// The minimum width (in pixels) of each item. The default is NaN, in which case the width
/// of the first item is used as the minimum.
/// </value>
public double MinItemWidth
{
get => GetValue(MinItemWidthProperty);
set => SetValue(MinItemWidthProperty, value);
}
/// <summary>
/// Gets or sets the minimum space between items on the vertical axis.
/// </summary>
/// <remarks>
/// The spacing may exceed this minimum value when <see cref="ItemsJustification"/> is set
/// to SpaceEvenly, SpaceAround, or SpaceBetween.
/// </remarks>
public double MinRowSpacing
{
get => GetValue(MinRowSpacingProperty);
set => SetValue(MinRowSpacingProperty, value);
}
/// <summary>
/// Gets or sets the axis along which items are laid out.
/// </summary>
/// <value>
/// One of the enumeration values that specifies the axis along which items are laid out.
/// The default is Vertical.
/// </value>
public Orientation Orientation
{
get => GetValue(OrientationProperty);

3
src/Avalonia.Controls/Repeaters/UniformGridLayoutState.cs

@ -10,6 +10,9 @@ using System.Text;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the state of a <see cref="UniformGridLayout"/>.
/// </summary>
public class UniformGridLayoutState
{
// We need to measure the element at index 0 to know what size to measure all other items.

68
src/Avalonia.Controls/Repeaters/VirtualizingLayout.cs

@ -3,47 +3,109 @@
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
namespace Avalonia.Controls.Repeaters
{
/// <summary>
/// Represents the base class for an object that sizes and arranges child elements for a host
/// and supports virtualization.
/// </summary>
public abstract class VirtualizingLayout : Layout
{
/// <inheritdoc/>
public sealed override void InitializeForContext(LayoutContext context)
{
InitializeForContextCore((VirtualizingLayoutContext)context);
}
/// <inheritdoc/>
public sealed override void UninitializeForContext(LayoutContext context)
{
UninitializeForContextCore((VirtualizingLayoutContext)context);
}
/// <inheritdoc/>
public sealed override Size Measure(LayoutContext context, Size availableSize)
{
return MeasureOverride((VirtualizingLayoutContext)context, availableSize);
}
/// <inheritdoc/>
public sealed override Size Arrange(LayoutContext context, Size finalSize)
{
return ArrangeOverride((VirtualizingLayoutContext)context, finalSize);
}
/// <summary>
/// When overridden in a derived class, initializes any per-container state the layout
/// requires when it is attached to an IControl container.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
protected virtual void InitializeForContextCore(VirtualizingLayoutContext context)
{
}
/// <summary>
/// When overridden in a derived class, removes any state the layout previously stored on
/// the IControl container.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
protected virtual void UninitializeForContextCore(VirtualizingLayoutContext context)
{
}
/// <summary>
/// Provides the behavior for the "Measure" pass of the layout cycle. Classes can override
/// this method to define their own "Measure" pass behavior.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <param name="availableSize">
/// The available size that this object can give to child objects. Infinity can be
/// specified as a value to indicate that the object will size to whatever content is
/// available.
/// </param>
/// <returns>
/// The size that this object determines it needs during layout, based on its calculations
/// of the allocated sizes for child objects or based on other considerations such as a
/// fixed container size.
/// </returns>
protected abstract Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize);
/// <summary>
/// When implemented in a derived class, provides the behavior for the "Arrange" pass of
/// layout. Classes can override this method to define their own "Arrange" pass behavior.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <param name="finalSize">
/// The final area within the container that this object should use to arrange itself and
/// its children.
/// </param>
/// <returns>The actual size that is used after the element is arranged in layout.</returns>
protected virtual Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) => finalSize;
/// <summary>
/// Notifies the layout when the data collection assigned to the container element (Items)
/// has changed.
/// </summary>
/// <param name="context">
/// The context object that facilitates communication between the layout and its host
/// container.
/// </param>
/// <param name="source">The data source.</param>
/// <param name="args">Data about the collection change.</param>
protected internal virtual void OnItemsChangedCore(
VirtualizingLayoutContext context,
object source,

Loading…
Cancel
Save