diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ImageIndexEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ImageIndexEditor.cs
new file mode 100644
index 00000000000..14a5d814b5c
--- /dev/null
+++ b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ImageIndexEditor.cs
@@ -0,0 +1,220 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Design;
+
+namespace System.Windows.Forms.Design
+{
+ ///
+ /// Provides an editor for visually picking an image index.
+ ///
+ internal class ImageIndexEditor : UITypeEditor
+ {
+ protected ImageList currentImageList;
+ protected WeakReference currentImageListPropRef;
+ protected object currentInstance;
+ protected UITypeEditor imageEditor;
+ protected string parentImageListProperty = "Parent";
+ // disable csharp compiler warning #0414: field assigned unused value
+ protected string imageListPropertyName = null;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ImageIndexEditor()
+ {
+ // Get the type editor for images. We use the properties on
+ // this to determine if we support value painting, etc.
+ imageEditor = (UITypeEditor)TypeDescriptor.GetEditor(typeof(Image), typeof(UITypeEditor));
+ }
+
+ internal UITypeEditor ImageEditor
+ {
+ get => imageEditor;
+ }
+
+ internal string ParentImageListProperty
+ {
+ get => parentImageListProperty;
+ }
+
+ ///
+ /// Retrieves an image for the current context at current index.
+ ///
+ protected virtual Image GetImage(ITypeDescriptorContext context, int index, string key, bool useIntIndex)
+ {
+ Image image = null;
+ object instance = context.Instance;
+
+ // we would not know what to do in this case anyway (i.e. multiple selection of objects)
+ if (instance is object[])
+ {
+ return null;
+ }
+
+ // If the instances are different, then we need to re-aquire our image list.
+ if ((index >= 0) || (key != null))
+ {
+ PropertyDescriptor currentImageListProp = null;
+ if (currentImageListPropRef != null)
+ {
+ currentImageListProp = currentImageListPropRef.Target as PropertyDescriptor;
+ }
+ if (currentImageList == null ||
+ instance != currentInstance ||
+ (currentImageListProp != null && (ImageList)currentImageListProp.GetValue(currentInstance) != currentImageList))
+ {
+
+ currentInstance = instance;
+ // first look for an attribute
+ PropertyDescriptor imageListProp = GetImageListProperty(context.PropertyDescriptor, ref instance);
+
+ // not found as an attribute, do the old behavior
+ while (instance != null && imageListProp == null)
+ {
+ PropertyDescriptorCollection props = TypeDescriptor.GetProperties(instance);
+
+ foreach (PropertyDescriptor prop in props)
+ {
+ if (typeof(ImageList).IsAssignableFrom(prop.PropertyType))
+ {
+ imageListProp = prop;
+ break;
+ }
+ }
+
+ if (imageListProp == null)
+ {
+
+ // We didn't find the image list in this component. See if the
+ // component has a "parent" property. If so, walk the tree...
+ PropertyDescriptor parentProp = props[ParentImageListProperty];
+ if (parentProp != null)
+ {
+ instance = parentProp.GetValue(instance);
+ }
+ else
+ {
+ // Stick a fork in us, we're done.
+ instance = null;
+ }
+ }
+ }
+
+ if (imageListProp != null)
+ {
+ currentImageList = (ImageList)imageListProp.GetValue(instance);
+ currentImageListPropRef = new WeakReference(imageListProp);
+ currentInstance = instance;
+ }
+ }
+
+ if (currentImageList != null)
+ {
+ if (useIntIndex)
+ {
+ if (currentImageList != null && index < currentImageList.Images.Count)
+ {
+ index = (index > 0) ? index : 0;
+ image = currentImageList.Images[index];
+ }
+ }
+ else
+ {
+ image = currentImageList.Images[key];
+ }
+ }
+ else
+ {
+ // no image list, no image
+ image = null;
+ }
+ }
+
+ return image;
+ }
+
+ ///
+ /// Gets a value indicating whether this editor supports the painting of a representation of an object's value.
+ ///
+ public override bool GetPaintValueSupported(ITypeDescriptorContext context)
+ => imageEditor != null ? imageEditor.GetPaintValueSupported(context) : false;
+
+ ///
+ /// Paints a representative value of the given object to the provided canvas. Painting should be done within the boundaries of the provided rectangle.
+ ///
+ public override void PaintValue(PaintValueEventArgs e)
+ {
+ if (ImageEditor != null)
+ {
+ Image image = null;
+
+ if (e.Value is int)
+ {
+ image = GetImage(e.Context, (int)e.Value, null, true);
+ }
+ else if (e.Value is string)
+ {
+ image = GetImage(e.Context, -1, (string)e.Value, false);
+ }
+
+ if (image != null)
+ {
+ ImageEditor.PaintValue(new PaintValueEventArgs(e.Context, image, e.Graphics, e.Bounds));
+ }
+ }
+ }
+
+ internal static PropertyDescriptor GetImageListProperty(PropertyDescriptor currentComponent, ref object instance)
+ {
+ //multiple selection is not supported by this class
+ if (instance is object[])
+ {
+ return null;
+ }
+
+ PropertyDescriptor imageListProp = null;
+ object parentInstance = instance;
+
+ RelatedImageListAttribute relILAttr = currentComponent.Attributes[typeof(RelatedImageListAttribute)] as RelatedImageListAttribute;
+ if (relILAttr != null)
+ {
+ var pathInfo = relILAttr.RelatedImageList.Split('.');
+ for (int i = 0; i < pathInfo.Length; i++)
+ {
+ if (parentInstance == null)
+ {
+ Debug.Fail("A property specified in the path is null or not yet instanciated at this time");
+ break; // path is wrong
+ }
+ var prop = TypeDescriptor.GetProperties(parentInstance)[pathInfo[i]];
+ if (prop == null)
+ {
+ Debug.Fail("The path specified to the property is wrong");
+ break; // path is wrong
+ }
+ if (i == pathInfo.Length - 1)
+ {
+ // we're on the last one, look if that's our guy
+ if (typeof(ImageList).IsAssignableFrom(prop.PropertyType))
+ {
+ instance = parentInstance;
+ imageListProp = prop;
+ break;
+ }
+ }
+ else
+ {
+ parentInstance = prop.GetValue(parentInstance);
+ }
+ }
+ }
+
+ return imageListProp;
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Design.Editors/tests/UnitTests/EnsureEditorsTests.cs b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/EnsureEditorsTests.cs
index 5cab02ac2d9..303468fd33d 100644
--- a/src/System.Windows.Forms.Design.Editors/tests/UnitTests/EnsureEditorsTests.cs
+++ b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/EnsureEditorsTests.cs
@@ -51,12 +51,12 @@ public void EnsureUITypeEditorForType(Type type, Type expectedEditorType)
[Theory]
//[InlineData(typeof(BindingSource), "DataMember", typeof(DataMemberListEditor))]
- //[InlineData(typeof(ButtonBase), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(ButtonBase), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ButtonBase), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ButtonBase), "ImageKey", typeof(ImageIndexEditor))]
[InlineData(typeof(ButtonBase), "Text", typeof(MultilineStringEditor))]
//[InlineData(typeof(CheckedListBox), "Items", typeof(ListControlStringCollectionEditor))]
- //[InlineData(typeof(ColumnHeader), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(ColumnHeader), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ColumnHeader), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ColumnHeader), "ImageKey", typeof(ImageIndexEditor))]
//[InlineData(typeof(ComboBox), "AutoCompleteCustomSource", typeof(ListControlStringCollectionEditor))]
//[InlineData(typeof(ComboBox), "Items", typeof(ListControlStringCollectionEditor))]
//[InlineData(typeof(DataGrid), "DataMember", typeof(DataMemberListEditor))]
@@ -74,8 +74,8 @@ public void EnsureUITypeEditorForType(Type type, Type expectedEditorType)
//[InlineData(typeof(ErrorProvider), "DataMember", typeof(DataMemberListEditor))]
//[InlineData(typeof(FolderBrowserDialog), "SelectedPath", typeof(SelectedPathEditor))]
//[InlineData(typeof(HelpProvider), "HelpNamespace", typeof(HelpNamespaceEditor))]
- //[InlineData(typeof(Label), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(Label), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(Label), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(Label), "ImageKey", typeof(ImageIndexEditor))]
[InlineData(typeof(Label), "Text", typeof(MultilineStringEditor))]
//[InlineData(typeof(LinkLabel), "LinkArea", typeof(LinkAreaEditor))]
//[InlineData(typeof(ListBox), "Items", typeof(ListControlStringCollectionEditor))]
@@ -85,22 +85,22 @@ public void EnsureUITypeEditorForType(Type type, Type expectedEditorType)
//[InlineData(typeof(ListView), "Columns", typeof(ColumnHeaderCollectionEditor))]
//[InlineData(typeof(ListView), "Groups", typeof(ListViewGroupCollectionEditor))]
//[InlineData(typeof(ListView), "Items", typeof(ListViewItemCollectionEditor))]
- //[InlineData(typeof(ListViewItem), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(ListViewItem), "ImageKey", typeof(ImageIndexEditor))]
- //[InlineData(typeof(ListViewItem), "StateImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ListViewItem), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ListViewItem), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ListViewItem), "StateImageIndex", typeof(ImageIndexEditor))]
//[InlineData(typeof(ListViewItem), "SubItems", typeof(ListViewSubItemCollectionEditor))]
//[InlineData(typeof(MaskedTextBox), "Mask", typeof(MaskPropertyEditor))]
//[InlineData(typeof(MaskedTextBox), "Text", typeof(MaskedTextBoxTextEditor))]
[InlineData(typeof(NotifyIcon), "BalloonTipText", typeof(MultilineStringEditor))]
[InlineData(typeof(NotifyIcon), "Text", typeof(MultilineStringEditor))]
//[InlineData(typeof(TabControl), "TabPages", typeof(TabPageCollectionEditor))]
- //[InlineData(typeof(TabPage), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TabPage), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TabPage), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TabPage), "ImageKey", typeof(ImageIndexEditor))]
//[InlineData(typeof(TextBox), "AutoCompleteCustomSource", typeof(ListControlStringCollectionEditor))]
[InlineData(typeof(TextBoxBase), "Lines", typeof(StringArrayEditor))]
[InlineData(typeof(TextBoxBase), "Text", typeof(MultilineStringEditor))]
- //[InlineData(typeof(ToolBarButton), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(ToolBarButton), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ToolBarButton), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(ToolBarButton), "ImageKey", typeof(ImageIndexEditor))]
//[InlineData(typeof(ToolStripComboBox), "AutoCompleteCustomSource", typeof(ListControlStringCollectionEditor))]
//[InlineData(typeof(ToolStripComboBox), "Items", typeof(ListControlStringCollectionEditor))]
//[InlineData(typeof(ToolStripItem), "ImageIndex", typeof(ToolStripImageIndexEditor))]
@@ -108,16 +108,16 @@ public void EnsureUITypeEditorForType(Type type, Type expectedEditorType)
[InlineData(typeof(ToolStripItem), "ToolTipText", typeof(MultilineStringEditor))]
//[InlineData(typeof(ToolStripTextBox), "AutoCompleteCustomSource", typeof(ListControlStringCollectionEditor))]
[InlineData(typeof(ToolStripTextBox), "Lines", typeof(StringArrayEditor))]
- //[InlineData(typeof(TreeNode), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeNode), "ImageKey", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeNode), "ImageIndexEditor", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeNode), "SelectedImageKey", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeNode), "StateImageKey", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeNode), "StateImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeView), "ImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeView), "ImageKey", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeView), "SelectedImageIndex", typeof(ImageIndexEditor))]
- //[InlineData(typeof(TreeView), "SelectedImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "ImageIndexEditor", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "SelectedImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "StateImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeNode), "StateImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeView), "ImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeView), "ImageKey", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeView), "SelectedImageIndex", typeof(ImageIndexEditor))]
+ [InlineData(typeof(TreeView), "SelectedImageKey", typeof(ImageIndexEditor))]
public void EnsureUITypeEditorForProperty(Type type, string propertyName, Type expectedEditorType)
{
var properties = TypeDescriptor.GetProperties(type);