Browse Source

Refactored ItemSourceView.

- Inner list needs to be a non-generic `IList` because `IList<T>` is no covariant.
- Moved out of the Repeater directory as it's now general-purpose.
pull/4533/head
Steven Kirk 6 years ago
parent
commit
c1b2e2d44d
  1. 32
      src/Avalonia.Controls/ItemsSourceView.cs

32
src/Avalonia.Controls/Repeater/ItemsSourceView.cs → src/Avalonia.Controls/ItemsSourceView.cs

@ -15,23 +15,17 @@ using Avalonia.Controls.Utils;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// Represents a standardized view of the supported interactions between a given ItemsSource /// Represents a standardized view of the supported interactions between a given
/// object and an <see cref="ItemsRepeater"/> control. /// <see cref="ItemsControl"/> or <see cref="ItemsRepeater"/> and its items.
/// </summary> /// </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<T> : INotifyCollectionChanged, IDisposable, IReadOnlyList<T> public class ItemsSourceView<T> : INotifyCollectionChanged, IDisposable, IReadOnlyList<T>
{ {
/// <summary> /// <summary>
/// Gets an empty <see cref="ItemsSourceView"/> /// Gets an empty <see cref="ItemsSourceView{T}"/>
/// </summary> /// </summary>
public static ItemsSourceView<T> Empty { get; } = new ItemsSourceView<T>(Array.Empty<T>()); public static ItemsSourceView<T> Empty { get; } = new ItemsSourceView<T>(Array.Empty<T>());
private readonly IList<T> _inner; private readonly IList _inner;
private INotifyCollectionChanged? _notifyCollectionChanged; private INotifyCollectionChanged? _notifyCollectionChanged;
/// <summary> /// <summary>
@ -47,17 +41,17 @@ namespace Avalonia.Controls
{ {
source = source ?? throw new ArgumentNullException(nameof(source)); source = source ?? throw new ArgumentNullException(nameof(source));
if (source is IList<T> list) if (source is IList list)
{ {
_inner = list; _inner = list;
} }
else if (source is IEnumerable<T> objectEnumerable) else if (source is IEnumerable<object?> enumerable)
{ {
_inner = new List<T>(objectEnumerable); _inner = new List<object?>(enumerable);
} }
else else
{ {
_inner = new List<T>(source.Cast<T>()); _inner = new List<object?>(source.Cast<object?>());
} }
ListenToCollectionChanges(); ListenToCollectionChanges();
@ -102,9 +96,9 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The item.</returns> /// <returns>The item.</returns>
public T GetAt(int index) => _inner[index]; public T GetAt(int index) => _inner is IList<T> typed ? typed[index] : (T)_inner[index];
public int IndexOf(T item) => _inner.IndexOf(item); public int IndexOf(object? item) => _inner.IndexOf(item);
public static ItemsSourceView<T> GetOrCreate(IEnumerable<T>? items) public static ItemsSourceView<T> GetOrCreate(IEnumerable<T>? items)
{ {
@ -148,7 +142,9 @@ namespace Avalonia.Controls
throw new NotImplementedException(); throw new NotImplementedException();
} }
public IEnumerator<T> GetEnumerator() => _inner.GetEnumerator(); public IEnumerator<T> GetEnumerator() => _inner is IList<T> typed ?
typed.GetEnumerator() : _inner.Cast<T>().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator();
internal void AddListener(ICollectionChangedListener listener) internal void AddListener(ICollectionChangedListener listener)
@ -187,7 +183,7 @@ namespace Avalonia.Controls
} }
} }
public class ItemsSourceView : ItemsSourceView<object> public class ItemsSourceView : ItemsSourceView<object?>
{ {
public ItemsSourceView(IEnumerable source) public ItemsSourceView(IEnumerable source)
: base(source) : base(source)
Loading…
Cancel
Save