Просмотр исходного кода

Added docs for ItemsRepeater-related classes.

Steven Kirk 6 лет назад
Родитель
Сommit
3a2876f1ef

+ 0 - 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

+ 105 - 3
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 - 0
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 - 0
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)

+ 9 - 4
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)

+ 48 - 1
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();

+ 78 - 1
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);
     }
 }

+ 10 - 4
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; }
     }
 }

+ 4 - 4
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
     {
     }

+ 25 - 2
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 - 0
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 - 0
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 - 0
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. 

+ 65 - 3
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,