| File: System\Windows\Forms\Design\ImageIndexEditor.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Drawing; using System.Drawing.Design; namespace System.Windows.Forms.Design; /// <summary> /// Provides an editor for visually picking an image index. /// </summary> internal class ImageIndexEditor : UITypeEditor { protected ImageList? _currentImageList; protected WeakReference<PropertyDescriptor>? _currentImageListPropertyReference; protected object? _currentInstance; protected string _parentImageListProperty = "Parent"; protected string? _imageListPropertyName; /// <summary> /// Initializes a new instance of the <see cref="ImageIndexEditor"/> class. /// </summary> public ImageIndexEditor() { // Get the type editor for images. We use the properties on this to determine if we support value painting, etc. ImageEditor = TypeDescriptorHelper.GetEditor<UITypeEditor>(typeof(Image)); } internal UITypeEditor? ImageEditor { get; } internal string ParentImageListProperty => _parentImageListProperty; /// <summary> /// Retrieves an image for the current context at current index. /// </summary> protected virtual Image? GetImage(ITypeDescriptorContext context, int index, string? key, bool useIntIndex) { 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[] || (index < 0 && key is null)) { return null; } // If the instances are different, then we need to re-acquire our image list. if (_currentImageList is null || instance != _currentInstance || (_currentImageListPropertyReference is not null && _currentImageListPropertyReference.TryGetTarget(out PropertyDescriptor? currentProperty) && (ImageList?)currentProperty.GetValue(_currentInstance) != _currentImageList)) { _currentInstance = instance; // First look for an attribute. PropertyDescriptor? imageListProperty = GetImageListProperty(context.PropertyDescriptor!, ref instance); // Not found as an attribute, do the old behavior. while (instance is not null && imageListProperty is null) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(instance); foreach (PropertyDescriptor property in properties) { if (typeof(ImageList).IsAssignableFrom(property.PropertyType)) { imageListProperty = property; break; } } if (imageListProperty is null) { // We didn't find the image list in this component. See if the // component has a "parent" property. If so, walk the tree. instance = properties[ParentImageListProperty]?.GetValue(instance); } } if (imageListProperty is not null) { _currentImageList = (ImageList?)imageListProperty.GetValue(instance); _currentImageListPropertyReference = new WeakReference<PropertyDescriptor>(imageListProperty); _currentInstance = instance; } } if (_currentImageList is not null) { if (useIntIndex) { if (index < _currentImageList.Images.Count) { return _currentImageList.Images[index]; } } else { return _currentImageList.Images[key!]; } } return null; } /// <inheritdoc /> public override bool GetPaintValueSupported(ITypeDescriptorContext? context) => ImageEditor?.GetPaintValueSupported(context) ?? false; /// <inheritdoc /> public override void PaintValue(PaintValueEventArgs e) { if (ImageEditor is null) { return; } Image? image = null; if (e.Value is int integer) { image = GetImage(e.Context!, integer, null, true); } else if (e.Value is string text) { image = GetImage(e.Context!, -1, text, false); } if (image is not 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[] || !currentComponent.TryGetAttribute(out RelatedImageListAttribute? imageListAttribute)) { return null; } object? parentInstance = instance; if (imageListAttribute.RelatedImageList is null) { return null; } string[] pathInfo = imageListAttribute.RelatedImageList.Split('.'); for (int i = 0; i < pathInfo.Length; i++) { if (parentInstance is null) { Debug.Fail("A property specified in the path is null or not yet instantiated at this time."); break; } PropertyDescriptor? property = TypeDescriptor.GetProperties(parentInstance)[pathInfo[i]]; if (property is null) { Debug.Fail("The path specified to the property is wrong."); break; } if (i == pathInfo.Length - 1) { // We're on the last one, look if that's our match. if (typeof(ImageList).IsAssignableFrom(property.PropertyType)) { instance = parentInstance; return property; } } else { parentInstance = property.GetValue(parentInstance); } } return null; } }