Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convenience / perf methods to ListViewItem/ControlCollection #10944

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/System.Windows.Forms/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
System.Windows.Forms.ListView.ListViewItemCollection.AddRange(System.Collections.Generic.IEnumerable<System.Windows.Forms.ListViewItem!>! collection) -> void
System.Windows.Forms.ListView.ListViewItemCollection.CopyTo(System.Windows.Forms.ListViewItem![]! array, int arrayIndex) -> void
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ namespace System.Windows.Forms;
public partial class Control
{
/// <summary>
/// Collection of controls...
/// Collection of controls.
/// </summary>
[ListBindable(false)]
public partial class ControlCollection : ArrangedElementCollection, IList, ICloneable
public partial class ControlCollection : ArrangedElementCollection, IList, IEnumerable<Control>, ICloneable
{
/// A caching mechanism for key accessor
/// We use an index here rather than control so that we don't have lifetime
Expand All @@ -29,10 +29,7 @@ public ControlCollection(Control owner)
/// <summary>
/// Returns true if the collection contains an item with the specified key, false otherwise.
/// </summary>
public virtual bool ContainsKey(string? key)
{
return IsValidIndex(IndexOfKey(key));
}
public virtual bool ContainsKey(string? key) => IsValidIndex(IndexOfKey(key));

/// <summary>
/// Adds a child control to this control. The control becomes the last control in
Expand Down Expand Up @@ -156,11 +153,23 @@ object ICloneable.Clone()
{
// Use CreateControlInstance so we get the same type of ControlCollection, but whack the
// owner so adding controls to this new collection does not affect the control we cloned from.
ControlCollection ccOther = Owner.CreateControlsInstance();
ControlCollection clone = Owner.CreateControlsInstance();

// We add using InnerList to prevent unnecessary parent cycle checks, etc.
ccOther.InnerList.AddRange(InnerList);
return ccOther;
if (clone.InnerList is List<IArrangedElement> list)
{
list.AddRange(InnerList);
}
else
{
Debug.Fail("Unexpected InnerList type");
foreach (Control c in this)
{
clone.Add(c);
}
}

return clone;
}

public bool Contains(Control? control) => ((IList)InnerList).Contains(control);
Expand Down Expand Up @@ -224,10 +233,7 @@ private static void FindInternal(string key, bool searchAllChildren, ControlColl
}
}

public override IEnumerator GetEnumerator()
{
return new ControlCollectionEnumerator(this);
}
public override IEnumerator GetEnumerator() => new ControlCollectionEnumerator(this);

public int IndexOf(Control? control) => ((IList)InnerList).IndexOf(control);

Expand Down Expand Up @@ -269,10 +275,7 @@ public virtual int IndexOfKey(string? key)
/// <summary>
/// Determines if the index is valid for the collection.
/// </summary>
private bool IsValidIndex(int index)
{
return ((index >= 0) && (index < Count));
}
private bool IsValidIndex(int index) => (index >= 0) && (index < Count);

/// <summary>
/// Who owns this control collection.
Expand All @@ -285,10 +288,9 @@ private bool IsValidIndex(int index)
/// </summary>
public virtual void Remove(Control? value)
{
// Sanity check parameter
if (value is null)
{
return; // Don't do anything
return;
}

if (value.ParentInternal == Owner)
Expand Down Expand Up @@ -317,10 +319,7 @@ void IList.Remove(object? control)
}
}

public void RemoveAt(int index)
{
Remove(this[index]);
}
public void RemoveAt(int index) => Remove(this[index]);

/// <summary>
/// Removes the child control with the specified key.
Expand Down Expand Up @@ -394,7 +393,7 @@ public virtual void Clear()
/// Retrieves the index of the specified child control in this array. An ArgumentException
/// is thrown if child is not parented to this Control.
/// </summary>
public int GetChildIndex(Control child) => GetChildIndex(child, true);
public int GetChildIndex(Control child) => GetChildIndex(child, throwException: true);

/// <summary>
/// Retrieves the index of the specified child control in this array. An ArgumentException
Expand Down Expand Up @@ -444,5 +443,13 @@ internal virtual void SetChildIndexInternal(Control child, int newIndex)
/// </summary>
public virtual void SetChildIndex(Control child, int newIndex) =>
SetChildIndexInternal(child, newIndex);

IEnumerator<Control> IEnumerable<Control>.GetEnumerator()
{
foreach (Control control in InnerList)
{
yield return control;
}
}
}
}
10 changes: 2 additions & 8 deletions src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4695,20 +4695,14 @@ public bool Contains([NotNullWhen(true)] Control? ctl)
/// should not call base.CreateAccessibilityObject.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual AccessibleObject CreateAccessibilityInstance()
{
return new ControlAccessibleObject(this);
}
protected virtual AccessibleObject CreateAccessibilityInstance() => new ControlAccessibleObject(this);

/// <summary>
/// Constructs the new instance of the Controls collection objects. Subclasses
/// should not call base.CreateControlsInstance.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual ControlCollection CreateControlsInstance()
{
return new ControlCollection(this);
}
protected virtual ControlCollection CreateControlsInstance() => new ControlCollection(this);

/// <summary>
/// Creates a Graphics for this control. The control's brush, font, foreground
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public partial class ListView
/// Represents the collection of items in a ListView or ListViewGroup
/// </summary>
[ListBindable(false)]
public partial class ListViewItemCollection : IList
public partial class ListViewItemCollection : IList, IList<ListViewItem>
{
/// A caching mechanism for key accessor
/// We use an index here rather than control so that we don't have lifetime
Expand Down Expand Up @@ -75,10 +75,7 @@ internal ListViewItemCollection(IInnerList innerList)

object? IList.this[int index]
{
get
{
return this[index];
}
get => this[index];
set
{
this[index] = value is ListViewItem item
Expand Down Expand Up @@ -116,10 +113,7 @@ internal ListViewItemCollection(IInnerList innerList)
/// the correct sorted position, or, if no sorting is set, at the end
/// of the list.
/// </summary>
public virtual ListViewItem Add(string? text)
{
return Add(text, -1);
}
public virtual ListViewItem Add(string? text) => Add(text, -1);

int IList.Add(object? item)
{
Expand Down Expand Up @@ -159,8 +153,6 @@ public virtual ListViewItem Add(ListViewItem value)
return value;
}

// <-- NEW ADD OVERLOADS IN WHIDBEY

/// <summary>
/// Add an item to the ListView. The item will be inserted either in
/// the correct sorted position, or, if no sorting is set, at the end
Expand Down Expand Up @@ -203,8 +195,6 @@ public virtual ListViewItem Add(string? key, string? text, int imageIndex)
return item;
}

// END - NEW ADD OVERLOADS IN WHIDBEY -->

public void AddRange(params ListViewItem[] items)
{
ArgumentNullException.ThrowIfNull(items);
Expand All @@ -224,10 +214,7 @@ public void AddRange(ListViewItemCollection items)
/// <summary>
/// Removes all items from the list view.
/// </summary>
public virtual void Clear()
{
InnerList.Clear();
}
public virtual void Clear() => InnerList.Clear();

public bool Contains(ListViewItem item)
{
Expand Down Expand Up @@ -335,7 +322,7 @@ public virtual int IndexOfKey(string? key)
// step 1 - check the last cached item
if (IsValidIndex(_lastAccessedIndex))
{
if (WindowsFormsUtils.SafeCompareStrings(this[_lastAccessedIndex].Name, key, /* ignoreCase = */ true))
if (WindowsFormsUtils.SafeCompareStrings(this[_lastAccessedIndex].Name, key, ignoreCase: true))
{
return _lastAccessedIndex;
}
Expand All @@ -344,7 +331,7 @@ public virtual int IndexOfKey(string? key)
// step 2 - search for the item
for (int i = 0; i < Count; i++)
{
if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true))
if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, ignoreCase: true))
{
_lastAccessedIndex = i;
return i;
Expand Down Expand Up @@ -395,8 +382,6 @@ void IList.Insert(int index, object? item)
}
}

// <-- NEW INSERT OVERLOADS IN WHIDBEY

public ListViewItem Insert(int index, string? text, string? imageKey)
=> Insert(index, new ListViewItem(text, imageKey));

Expand All @@ -412,8 +397,6 @@ public virtual ListViewItem Insert(int index, string? key, string? text, int ima
Name = key
});

// END - NEW INSERT OVERLOADS IN WHIDBEY -->

/// <summary>
/// Removes an item from the ListView
/// </summary>
Expand Down Expand Up @@ -452,5 +435,42 @@ void IList.Remove(object? item)
Remove(listViewItem);
}
}

void IList<ListViewItem>.Insert(int index, ListViewItem item) => Insert(index, item);

void ICollection<ListViewItem>.Add(ListViewItem item) => Add(item);

public void CopyTo(ListViewItem[] array, int arrayIndex) => CopyTo((Array)array, arrayIndex);

bool ICollection<ListViewItem>.Remove(ListViewItem item)
{
if (Contains(item))
{
Remove(item);
return true;
}

return false;
}

IEnumerator<ListViewItem> IEnumerable<ListViewItem>.GetEnumerator()
{
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is ListViewItem item)
{
yield return item;
}
}
}

public void AddRange(IEnumerable<ListViewItem> collection)
{
foreach (ListViewItem item in collection)
{
Add(item);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ internal override void AddInternal(Control? value)

internal void Sort()
{
if (_owner.Orientation == Orientation.Horizontal)
if (InnerList is not List<IArrangedElement> list)
{
InnerList.Sort(new YXComparer());
}
else
{
InnerList.Sort(new XYComparer());
Debug.Fail("InnerList is not a List<IArrangedElement>?");
return;
}

list.Sort(_owner.Orientation == Orientation.Horizontal ? new YXComparer() : new XYComparer());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ namespace System.Windows.Forms.Layout;

public class ArrangedElementCollection : IList
{
internal static ArrangedElementCollection Empty { get; } = new(0);
internal static ArrangedElementCollection Empty { get; } = new(new List<IArrangedElement>().AsReadOnly());

internal ArrangedElementCollection() : this(4)
{
}

internal ArrangedElementCollection(List<IArrangedElement> innerList) => InnerList = innerList;
internal ArrangedElementCollection(IList<IArrangedElement> innerList) => InnerList = innerList;

private ArrangedElementCollection(int size) => InnerList = new List<IArrangedElement>(size);

private protected List<IArrangedElement> InnerList { get; }
private protected IList<IArrangedElement> InnerList { get; }

internal virtual IArrangedElement this[int index] => InnerList[index];

Expand Down Expand Up @@ -93,7 +93,12 @@ private protected void MoveElement(IArrangedElement element, int fromIndex, int
InnerList[toIndex] = element;
}

private static void Copy(ArrangedElementCollection sourceList, int sourceIndex, ArrangedElementCollection destinationList, int destinationIndex, int length)
private static void Copy(
ArrangedElementCollection sourceList,
int sourceIndex,
ArrangedElementCollection destinationList,
int destinationIndex,
int length)
{
if (sourceIndex < destinationIndex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static void ValidateResult(string blob)
Assert.Equal(HorizontalAlignment.Center, result.HeaderAlignment);
Assert.Equal("Tag", result.Tag);
Assert.Equal("GroupName", result.Name);
var item = Assert.Single(result.Items) as ListViewItem;
var item = Assert.Single(result.Items);
Assert.NotNull(item);
Assert.Equal("Item", item.Text);
}
Expand Down