diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/AdapterHelpers.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/AdapterHelpers.cs
new file mode 100644
index 00000000000..157d145d49f
--- /dev/null
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/AdapterHelpers.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections;
+
+namespace System.Windows.Forms.Design;
+
+///
+/// Helpers for adapting between generic and non-generic lists.
+///
+internal static class AdapterHelpers
+{
+ ///
+ /// Provides an extension method to safely extract the underlying non-generic
+ /// from a wrapped when available.
+ ///
+ /// The type of elements in the .
+ /// The IList<T> to unwrap.
+ /// The underlying non-generic if available; otherwise, the original .
+ internal static IList Unwrap(this IList list) => list is IWrapper wrapper ? wrapper.Unwrap() : (IList)list;
+
+ ///
+ /// Provides an extension method to adapt a non-generic IList to a generic by creating
+ /// a when needed.
+ ///
+ /// The desired type of elements in the resulting .
+ /// The non-generic to adapt.
+ ///
+ /// A generic if the input IList can be cast to otherwise, a new wrapping the input IList.
+ ///
+ internal static IList Adapt(this IList list) => list is IList iList ? iList : new ListAdapter(list);
+}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/BehaviorService.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/BehaviorService.cs
index f09a3a01863..dea43a0f423 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/BehaviorService.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/BehaviorService.cs
@@ -816,7 +816,7 @@ private void TestHook_GetAllSnapLines(ref Message m)
if (host.GetDesigner(comp) is ControlDesigner designer)
{
- foreach (SnapLine line in designer.SnapLines)
+ foreach (SnapLine line in designer.SnapLinesInternal)
{
snapLineInfo.Append($"{line}\tAssociated Control = {designer.Control.Name}:::");
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/DragAssistanceManager.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/DragAssistanceManager.cs
index 36e0e9aa9b8..b28691cc26c 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/DragAssistanceManager.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/Behavior/DragAssistanceManager.cs
@@ -130,7 +130,7 @@ internal DragAssistanceManager(IServiceProvider serviceProvider, Graphics graphi
///
private void AddSnapLines(ControlDesigner controlDesigner, List horizontalList, List verticalList, bool isTarget, bool validTarget)
{
- IList snapLines = controlDesigner.SnapLines;
+ IList snapLines = controlDesigner.SnapLinesInternal;
// Used for padding snaplines
Rectangle controlRect = controlDesigner.Control.ClientRectangle;
// Used for all others
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ButtonBaseDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ButtonBaseDesigner.cs
index 335bed4f3d6..2036f051535 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ButtonBaseDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ButtonBaseDesigner.cs
@@ -49,7 +49,7 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = base.SnapLines as ArrayList;
+ IList snapLines = SnapLinesInternal;
FlatStyle flatStyle = FlatStyle.Standard;
ContentAlignment alignment = ContentAlignment.MiddleCenter;
@@ -103,7 +103,7 @@ public override IList SnapLines
snapLines.Add(new SnapLine(SnapLineType.Baseline, baseline, SnapLinePriority.Medium));
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ComboBoxDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ComboBoxDesigner.cs
index 029f259611e..635dca98068 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ComboBoxDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ComboBoxDesigner.cs
@@ -27,14 +27,14 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = base.SnapLines as ArrayList;
+ IList snapLines = SnapLinesInternal;
// a single text-baseline for the label (and linklabel) control
int baseline = DesignerUtils.GetTextBaseline(Control, Drawing.ContentAlignment.TopLeft);
baseline += 3;
snapLines.Add(new SnapLine(SnapLineType.Baseline, baseline, SnapLinePriority.Medium));
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ControlDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ControlDesigner.cs
index 5c2007a773b..ea40f967834 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ControlDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ControlDesigner.cs
@@ -356,13 +356,15 @@ private bool IsResizableConsiderAutoSize(PropertyDescriptor autoSizeProp, Proper
/// Returns a list of SnapLine objects representing interesting alignment points for this control.
/// These SnapLines are used to assist in the positioning of the control on a parent's surface.
///
- public virtual IList SnapLines => SnapLinesInternal();
+ public virtual IList SnapLines => EdgeAndMarginSnapLines().Unwrap();
- internal IList SnapLinesInternal() => SnapLinesInternal(Control.Margin);
+ internal IList SnapLinesInternal => SnapLines.Adapt();
- internal IList SnapLinesInternal(Padding margin)
+ internal IList EdgeAndMarginSnapLines() => EdgeAndMarginSnapLines(Control.Margin);
+
+ internal IList EdgeAndMarginSnapLines(Padding margin)
{
- ArrayList snapLines = new(4);
+ List snapLines = new(8);
int width = Control.Width;
int height = Control.Height;
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DateTimePickerDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DateTimePickerDesigner.cs
index 1fbaccd03a7..3b09ddc0ea8 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DateTimePickerDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DateTimePickerDesigner.cs
@@ -21,7 +21,7 @@ public override IList SnapLines
{
get
{
- IList snapLines = base.SnapLines;
+ IList snapLines = SnapLinesInternal;
// A single text-baseline for the label (and linklabel) control.
int baseline = DesignerUtils.GetTextBaseline(Control, ContentAlignment.MiddleLeft);
@@ -30,7 +30,7 @@ public override IList SnapLines
baseline += 2;
snapLines.Add(new SnapLine(SnapLineType.Baseline, baseline, SnapLinePriority.Medium));
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FlowPanelDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FlowPanelDesigner.cs
index c6d80b1f7f6..4e7bc403737 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FlowPanelDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FlowPanelDesigner.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable disable
-
using System.Collections;
using System.Windows.Forms.Design.Behavior;
@@ -16,25 +14,19 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = (ArrayList)base.SnapLines;
+ IList snapLines = SnapLinesInternal;
- // identify all the paddings to remove
- ArrayList paddingsToRemove = new(4);
- foreach (SnapLine line in snapLines)
+ // identify and remove all paddings
+ for (int i = snapLines.Count - 1; i >= 0; i--)
{
- if (line.Filter is not null && line.Filter.Contains(SnapLine.Padding))
+ if (snapLines[i] is SnapLine line
+ && line.Filter?.Contains(SnapLine.Padding) == true)
{
- paddingsToRemove.Add(line);
+ snapLines.RemoveAt(i);
}
}
- // remove all padding
- foreach (SnapLine line in paddingsToRemove)
- {
- snapLines.Remove(line);
- }
-
- return snapLines;
+ return snapLines.Unwrap();
}
}
@@ -48,7 +40,7 @@ protected override void OnDragDrop(DragEventArgs de)
{
base.OnDragDrop(de);
- SelectionManager sm = GetService(typeof(SelectionManager)) as SelectionManager;
+ SelectionManager? sm = GetService(typeof(SelectionManager)) as SelectionManager;
sm?.Refresh();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FormDocumentDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FormDocumentDesigner.cs
index 7aa0047b996..5a01206b02b 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FormDocumentDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FormDocumentDesigner.cs
@@ -181,12 +181,12 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = null;
+ IList snapLines = null;
AddPaddingSnapLines(ref snapLines);
if (snapLines is null)
{
Debug.Fail("why did base.AddPaddingSnapLines return null?");
- snapLines = new ArrayList(4);
+ snapLines = new List(4);
}
// if the padding has not been set - then we'll auto-add padding to form - this is a Usability request
@@ -218,7 +218,7 @@ public override IList SnapLines
}
}
- return snapLines;
+ return (IList)snapLines;
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/IWrapper.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/IWrapper.cs
new file mode 100644
index 00000000000..2de0e3067b1
--- /dev/null
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/IWrapper.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Windows.Forms.Design;
+
+///
+/// Interface to provide a contract to provide access to the underlying type.
+///
+/// The type of object being wrapped.
+internal interface IWrapper
+{
+ T Unwrap();
+}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/LabelDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/LabelDesigner.cs
index 3b8d6a3a99c..1fa0602e7c5 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/LabelDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/LabelDesigner.cs
@@ -31,7 +31,7 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = base.SnapLines as ArrayList;
+ IList snapLines = SnapLinesInternal;
ContentAlignment alignment = ContentAlignment.TopLeft;
PropertyDescriptor prop;
@@ -93,7 +93,7 @@ public override IList SnapLines
}
}
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ListAdapter.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ListAdapter.cs
new file mode 100644
index 00000000000..676b2fc23e0
--- /dev/null
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ListAdapter.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections;
+
+namespace System.Windows.Forms.Design;
+
+///
+/// Adapter for bridging between generic and non-generic lists.
+/// It implements both the generic and the non-generic
+/// interfaces
+/// to provide a unified interface for working with IList collections.
+///
+/// The type of elements in the list.
+internal sealed class ListAdapter : IList, IWrapper
+{
+ private readonly IList _list;
+ internal ListAdapter(IList list) => _list = list.OrThrowIfNull();
+
+ T IList.this[int index]
+ {
+ get => (T?)_list[index] ?? throw new InvalidOperationException();
+ set => _list[index] = value.OrThrowIfNull();
+ }
+
+ int ICollection.Count => _list.Count;
+
+ bool ICollection.IsReadOnly => _list.IsReadOnly;
+
+ void ICollection.Add(T item) => _list.Add(item.OrThrowIfNull());
+ void ICollection.Clear() => _list.Clear();
+ bool ICollection.Contains(T item) => _list.Contains(item);
+ void ICollection.CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
+ IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
+ int IList.IndexOf(T item) => _list.IndexOf(item);
+ void IList.Insert(int index, T item) => _list.Insert(index, item.OrThrowIfNull());
+ void IList.RemoveAt(int index) => _list.RemoveAt(index);
+
+ bool ICollection.Remove(T item)
+ {
+ if (_list.IsReadOnly || !_list.Contains(item))
+ {
+ return false;
+ }
+
+ _list.Remove(item);
+ return true;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_list.GetEnumerator());
+
+ private sealed class Enumerator(IEnumerator _enumerator) : IEnumerator
+ {
+ T IEnumerator.Current => (T)_enumerator.Current;
+ object IEnumerator.Current => _enumerator.Current;
+
+ void IDisposable.Dispose() { }
+ bool IEnumerator.MoveNext() => _enumerator.MoveNext();
+ void IEnumerator.Reset() => _enumerator.Reset();
+ }
+
+ public IList Unwrap() => _list;
+}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ParentControlDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ParentControlDesigner.cs
index 00f268f82e5..31d31a2793e 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ParentControlDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ParentControlDesigner.cs
@@ -295,9 +295,13 @@ protected Size GridSize
// We need to allocation new ArrayList and pass it to the caller..
// So its ok to Suppress this.
protected void AddPaddingSnapLines(ref ArrayList snapLines)
- {
- snapLines ??= new ArrayList(4);
+ => AddPaddingSnapLinesCommon((snapLines ??= new(4)).Adapt());
+
+ internal void AddPaddingSnapLines(ref IList snapLines)
+ => AddPaddingSnapLinesCommon(snapLines ??= new List(4));
+ private void AddPaddingSnapLinesCommon(IList snapLines)
+ {
// In order to add padding, we need to get the offset from the usable client area of our control
// and the actual origin of our control. In other words: how big is the non-client area here?
// Ex: we want to add padding on a form to the insides of the borders and below the titlebar.
@@ -328,16 +332,16 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = base.SnapLines as ArrayList;
+ IList snapLines = SnapLinesInternal;
if (snapLines is null)
{
Debug.Fail("why did base.SnapLines return null?");
- snapLines = new ArrayList(4);
+ snapLines = new List(4);
}
AddPaddingSnapLines(ref snapLines);
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SplitContainerDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SplitContainerDesigner.cs
index 2dfd2c9e174..10bbba5ab25 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SplitContainerDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SplitContainerDesigner.cs
@@ -61,7 +61,7 @@ internal partial class SplitContainerDesigner : ParentControlDesigner
///
public override IList SnapLines =>
// We don't want padding snaplines, so call directly to the internal method.
- SnapLinesInternal();
+ EdgeAndMarginSnapLines().Unwrap();
///
/// Returns the number of internal control designers in the . An internal control is a control that is not in the
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/TextBoxBaseDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/TextBoxBaseDesigner.cs
index 26efc159cee..59908835e4a 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/TextBoxBaseDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/TextBoxBaseDesigner.cs
@@ -28,12 +28,10 @@ public override IList SnapLines
{
int baseline = DesignerUtils.GetTextBaseline(Control, Drawing.ContentAlignment.TopLeft);
- BorderStyle borderStyle = BorderStyle.Fixed3D;
PropertyDescriptor? prop = TypeDescriptor.GetProperties(Component)["BorderStyle"];
- if (prop is not null)
- {
- borderStyle = (BorderStyle)prop.GetValue(Component)!;
- }
+ BorderStyle borderStyle = prop is not null
+ ? (BorderStyle)prop.GetValue(Component)!
+ : BorderStyle.Fixed3D;
if (borderStyle == BorderStyle.None)
{
@@ -53,11 +51,9 @@ public override IList SnapLines
baseline += 0;
}
- IList snapLines = base.SnapLines;
-
+ IList snapLines = SnapLinesInternal;
snapLines.Add(new SnapLine(SnapLineType.Baseline, baseline, SnapLinePriority.Medium));
-
- return snapLines;
+ return snapLines.Unwrap();
}
}
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ToolStripContainerDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ToolStripContainerDesigner.cs
index 1edc9de18e1..e20b278da1e 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ToolStripContainerDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ToolStripContainerDesigner.cs
@@ -117,7 +117,7 @@ public override DesignerActionListCollection ActionLists
public override IList SnapLines
// We don't want padding SnapLines, so call directly to the internal method.
- => SnapLinesInternal();
+ => EdgeAndMarginSnapLines().Unwrap();
///
/// Returns the internal control designer with the specified index in the ControlDesigner.
diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/UpDownBaseDesigner.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/UpDownBaseDesigner.cs
index b5a4ea24101..b38761f845c 100644
--- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/UpDownBaseDesigner.cs
+++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/UpDownBaseDesigner.cs
@@ -43,29 +43,17 @@ public override IList SnapLines
{
get
{
- ArrayList snapLines = base.SnapLines as ArrayList;
-
+ IList snapLines = SnapLinesInternal;
int baseline = DesignerUtils.GetTextBaseline(Control, Drawing.ContentAlignment.TopLeft);
- BorderStyle borderStyle = BorderStyle.Fixed3D;
PropertyDescriptor prop = TypeDescriptor.GetProperties(Component)["BorderStyle"];
- if (prop is not null)
- {
- borderStyle = (BorderStyle)prop.GetValue(Component);
- }
-
- if (borderStyle == BorderStyle.None)
- {
- baseline -= 1;
- }
- else
- {
- baseline += 2;
- }
+ BorderStyle borderStyle = prop is not null
+ ? (BorderStyle)prop.GetValue(Component)
+ : BorderStyle.Fixed3D;
+ baseline += borderStyle == BorderStyle.None ? -1 : 2;
snapLines.Add(new SnapLine(SnapLineType.Baseline, baseline, SnapLinePriority.Medium));
-
- return snapLines;
+ return snapLines.Unwrap();
}
}
}