committed by
GitHub
25 changed files with 663 additions and 314 deletions
@ -0,0 +1,5 @@ |
|||||
|
<ProjectConfiguration> |
||||
|
<Settings> |
||||
|
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
||||
|
</Settings> |
||||
|
</ProjectConfiguration> |
||||
@ -0,0 +1,5 @@ |
|||||
|
<ProjectConfiguration> |
||||
|
<Settings> |
||||
|
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
||||
|
</Settings> |
||||
|
</ProjectConfiguration> |
||||
@ -0,0 +1,165 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Specialized; |
||||
|
using System.Diagnostics.CodeAnalysis; |
||||
|
using Avalonia.Collections; |
||||
|
|
||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Holds the list of items that constitute the content of an <see cref="ItemsControl"/>.
|
||||
|
/// </summary>
|
||||
|
public class ItemCollection : ItemsSourceView, IList |
||||
|
{ |
||||
|
// Suppress "Avoid zero-length array allocations": This is a sentinel value and must be unique.
|
||||
|
#pragma warning disable CA1825
|
||||
|
private static readonly object?[] s_uninitialized = new object?[0]; |
||||
|
#pragma warning restore CA1825
|
||||
|
|
||||
|
private Mode _mode; |
||||
|
|
||||
|
internal ItemCollection() |
||||
|
: base(s_uninitialized) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new object? this[int index] |
||||
|
{ |
||||
|
get => base[index]; |
||||
|
set => WritableSource[index] = value; |
||||
|
} |
||||
|
|
||||
|
public bool IsReadOnly => _mode == Mode.ItemsSource; |
||||
|
|
||||
|
internal event EventHandler? SourceChanged; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds an item to the <see cref="ItemsControl"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">The item to add to the collection.</param>
|
||||
|
/// <returns>
|
||||
|
/// The position into which the new element was inserted, or -1 to indicate that
|
||||
|
/// the item was not inserted into the collection.
|
||||
|
/// </returns>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// The collection is in ItemsSource mode.
|
||||
|
/// </exception>
|
||||
|
public int Add(object? value) => WritableSource.Add(value); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Clears the collection and releases the references on all items currently in the
|
||||
|
/// collection.
|
||||
|
/// </summary>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// The collection is in ItemsSource mode.
|
||||
|
/// </exception>
|
||||
|
public void Clear() => WritableSource.Clear(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inserts an element into the collection at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">The zero-based index at which to insert the item.</param>
|
||||
|
/// <param name="value">The item to insert.</param>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// The collection is in ItemsSource mode.
|
||||
|
/// </exception>
|
||||
|
public void Insert(int index, object? value) => WritableSource.Insert(index, value); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the item at the specified index of the collection or view.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// The collection is in ItemsSource mode.
|
||||
|
/// </exception>
|
||||
|
public void RemoveAt(int index) => WritableSource.RemoveAt(index); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the specified item reference from the collection or view.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">The object to remove.</param>
|
||||
|
/// <returns>True if the item was removed; otherwise false.</returns>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// The collection is in ItemsSource mode.
|
||||
|
/// </exception>
|
||||
|
public bool Remove(object? value) |
||||
|
{ |
||||
|
var c = Count; |
||||
|
WritableSource.Remove(value); |
||||
|
return Count < c; |
||||
|
} |
||||
|
|
||||
|
int IList.Add(object? value) => Add(value); |
||||
|
void IList.Clear() => Clear(); |
||||
|
void IList.Insert(int index, object? value) => Insert(index, value); |
||||
|
void IList.RemoveAt(int index) => RemoveAt(index); |
||||
|
|
||||
|
private IList WritableSource |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (IsReadOnly) |
||||
|
ThrowIsItemsSource(); |
||||
|
if (Source == s_uninitialized) |
||||
|
SetSource(CreateDefaultCollection()); |
||||
|
return Source; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal IList? GetItemsPropertyValue() |
||||
|
{ |
||||
|
if (_mode == Mode.ObsoleteItemsSetter) |
||||
|
return Source == s_uninitialized ? null : Source; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
internal void SetItems(IList? items) |
||||
|
{ |
||||
|
_mode = Mode.ObsoleteItemsSetter; |
||||
|
SetSource(items ?? s_uninitialized); |
||||
|
} |
||||
|
|
||||
|
internal void SetItemsSource(IEnumerable? value) |
||||
|
{ |
||||
|
if (_mode != Mode.ItemsSource && Count > 0) |
||||
|
throw new InvalidOperationException( |
||||
|
"Items collection must be empty before using ItemsSource."); |
||||
|
|
||||
|
_mode = value is not null ? Mode.ItemsSource : Mode.Items; |
||||
|
SetSource(value ?? CreateDefaultCollection()); |
||||
|
} |
||||
|
|
||||
|
private new void SetSource(IEnumerable source) |
||||
|
{ |
||||
|
var oldSource = Source; |
||||
|
|
||||
|
base.SetSource(source); |
||||
|
|
||||
|
if (oldSource.Count > 0) |
||||
|
RaiseCollectionChanged(new(NotifyCollectionChangedAction.Remove, oldSource, 0)); |
||||
|
if (Source.Count > 0) |
||||
|
RaiseCollectionChanged(new(NotifyCollectionChangedAction.Add, Source, 0)); |
||||
|
SourceChanged?.Invoke(this, EventArgs.Empty); |
||||
|
} |
||||
|
|
||||
|
private static AvaloniaList<object?> CreateDefaultCollection() |
||||
|
{ |
||||
|
return new() { ResetBehavior = ResetBehavior.Remove }; |
||||
|
} |
||||
|
|
||||
|
[DoesNotReturn] |
||||
|
private static void ThrowIsItemsSource() |
||||
|
{ |
||||
|
throw new InvalidOperationException( |
||||
|
"Operation is not valid while ItemsSource is in use." + |
||||
|
"Access and modify elements with ItemsControl.ItemsSource instead."); |
||||
|
} |
||||
|
|
||||
|
private enum Mode |
||||
|
{ |
||||
|
Items, |
||||
|
ItemsSource, |
||||
|
ObsoleteItemsSetter, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue