< Summary - PropertyGridHelpers Code Coverage

Information
Class: PropertyGridHelpers.UIEditors.AutoCompleteComboBoxEditor
Assembly: PropertyGridHelpers
File(s): File 1: C:\Agent\_work\2\s\Code\PropertyGridHelpers\UIEditors\AutoCompleteComboBoxEditor.cs
File 2: C:\Agent\_work\2\s\Code\PropertyGridHelpers\UIEditors\AutoCompleteComboBoxEditorT.cs
Tag: PropertyGridHelpers Build_2026.1.11.1_#580
Line coverage
100%
Covered lines: 80
Uncovered lines: 0
Coverable lines: 80
Total lines: 266
Line coverage: 100%
Branch coverage
100%
Covered branches: 48
Total branches: 48
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/22/2025 - 7:52:21 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: PropertyGridHelpers Build_2025.5.22.1_#4175/23/2025 - 7:21:57 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: Test PropertyGridHelpers Build_2025.5.23.2_#4265/28/2025 - 8:07:03 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: PropertyGridHelpers Build_2025.5.28.1_#4286/3/2025 - 12:18:43 AM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: PropertyGridHelpers Build_2025.6.3.1_#4326/3/2025 - 4:27:27 PM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: Test PropertyGridHelpers Build_2025.6.3.1_#4336/3/2025 - 7:42:47 PM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: PropertyGridHelpers Build_2025.6.3.2_#4396/12/2025 - 9:38:24 PM Line coverage: 58.4% (38/65) Branch coverage: 50% (16/32) Total lines: 181 Tag: PropertyGridHelpers Build_2025.6.12.2_#4566/15/2025 - 1:46:04 AM Line coverage: 48.3% (44/91) Branch coverage: 36.3% (24/66) Total lines: 247 Tag: PropertyGridHelpers Build_2025.6.15.1_#4596/18/2025 - 11:42:34 PM Line coverage: 75.2% (67/89) Branch coverage: 86.2% (50/58) Total lines: 253 Tag: PropertyGridHelpers Build_2025.6.18.1_#4656/19/2025 - 1:31:04 PM Line coverage: 77.6% (66/85) Branch coverage: 87.5% (49/56) Total lines: 245 Tag: PropertyGridHelpers Build_2025.6.19.1_#4666/19/2025 - 7:15:54 PM Line coverage: 80% (64/80) Branch coverage: 90.3% (47/52) Total lines: 234 Tag: PropertyGridHelpers Build_2025.6.19.2_#4676/19/2025 - 9:13:57 PM Line coverage: 100% (78/78) Branch coverage: 100% (48/48) Total lines: 231 Tag: PropertyGridHelpers Build_2025.6.19.3_#4687/4/2025 - 11:01:20 PM Line coverage: 100% (78/78) Branch coverage: 100% (48/48) Total lines: 237 Tag: PropertyGridHelpers Build_2025.7.4.1_#4771/10/2026 - 4:46:27 PM Line coverage: 100% (80/80) Branch coverage: 100% (48/48) Total lines: 266 Tag: PropertyGridHelpers Build_2026.1.10.1_#579 5/22/2025 - 7:52:21 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: PropertyGridHelpers Build_2025.5.22.1_#4175/23/2025 - 7:21:57 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: Test PropertyGridHelpers Build_2025.5.23.2_#4265/28/2025 - 8:07:03 PM Line coverage: 0% (0/23) Branch coverage: 0% (0/16) Total lines: 94 Tag: PropertyGridHelpers Build_2025.5.28.1_#4286/3/2025 - 12:18:43 AM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: PropertyGridHelpers Build_2025.6.3.1_#4326/3/2025 - 4:27:27 PM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: Test PropertyGridHelpers Build_2025.6.3.1_#4336/3/2025 - 7:42:47 PM Line coverage: 100% (22/22) Branch coverage: 100% (10/10) Total lines: 91 Tag: PropertyGridHelpers Build_2025.6.3.2_#4396/12/2025 - 9:38:24 PM Line coverage: 58.4% (38/65) Branch coverage: 50% (16/32) Total lines: 181 Tag: PropertyGridHelpers Build_2025.6.12.2_#4566/15/2025 - 1:46:04 AM Line coverage: 48.3% (44/91) Branch coverage: 36.3% (24/66) Total lines: 247 Tag: PropertyGridHelpers Build_2025.6.15.1_#4596/18/2025 - 11:42:34 PM Line coverage: 75.2% (67/89) Branch coverage: 86.2% (50/58) Total lines: 253 Tag: PropertyGridHelpers Build_2025.6.18.1_#4656/19/2025 - 1:31:04 PM Line coverage: 77.6% (66/85) Branch coverage: 87.5% (49/56) Total lines: 245 Tag: PropertyGridHelpers Build_2025.6.19.1_#4666/19/2025 - 7:15:54 PM Line coverage: 80% (64/80) Branch coverage: 90.3% (47/52) Total lines: 234 Tag: PropertyGridHelpers Build_2025.6.19.2_#4676/19/2025 - 9:13:57 PM Line coverage: 100% (78/78) Branch coverage: 100% (48/48) Total lines: 231 Tag: PropertyGridHelpers Build_2025.6.19.3_#4687/4/2025 - 11:01:20 PM Line coverage: 100% (78/78) Branch coverage: 100% (48/48) Total lines: 237 Tag: PropertyGridHelpers Build_2025.7.4.1_#4771/10/2026 - 4:46:27 PM Line coverage: 100% (80/80) Branch coverage: 100% (48/48) Total lines: 266 Tag: PropertyGridHelpers Build_2026.1.10.1_#579

Metrics

MethodBlocks covered Blocks not covered Branch coverage Crap Score Cyclomatic complexity Line coverage
File 1: get_Converter()--100%11100%
File 1: EditValue(...)760----
File 1: EditValue(...)--100%1616100%
File 1: EditValue(...)690----
File 1: ResolveValues(...)180----
File 1: ResolveValues(...)--100%88100%
File 1: ResolveValues(...)170----
File 1: ValidateSetup(...)541----
File 1: ValidateSetup(...)--100%2424100%
File 1: ValidateSetup(...)451----
File 2: AutoCompleteComboBoxEditor()40----

File(s)

C:\Agent\_work\2\s\Code\PropertyGridHelpers\UIEditors\AutoCompleteComboBoxEditor.cs

#LineLine coverage
 1using PropertyGridHelpers.Attributes;
 2using PropertyGridHelpers.Controls;
 3using System;
 4using System.ComponentModel;
 5using System.Drawing.Design;
 6using System.Globalization;
 7using System.Linq;
 8using System.Reflection;
 9using System.Windows.Forms;
 10using System.Windows.Forms.Design;
 11
 12namespace PropertyGridHelpers.UIEditors
 13{
 14    /// <summary>
 15    /// Provides a <see cref="UITypeEditor"/> that shows an auto-complete-enabled drop-down list using an
 16    /// <see cref="AutoCompleteComboBox"/>, allowing quick selection of string values within a <see cref="PropertyGrid"/
 17    /// </summary>
 18    /// <remarks>
 19    /// This editor supports auto-complete behavior based on a configurable
 20    /// <see cref="AutoCompleteSource"/> and <see cref="AutoCompleteMode"/> as defined by the
 21    /// <see cref="AutoCompleteSetupAttribute"/>.
 22    ///
 23    /// For <see cref="AutoCompleteSource.CustomSource"/>, the list of suggestions can be provided:
 24    /// <list type="bullet">
 25    /// <item><description>Directly via string array</description></item>
 26    /// <item><description>From an enum's names</description></item>
 27    /// <item><description>From a public static <c>string[] Values</c> property on a class</description></item>
 28    /// </list>
 29    ///
 30    /// When configured with an enum type, the editor displays the enum's names, and returns the
 31    /// selected enum value rather than a string. Otherwise, the selected string is returned.
 32    /// </remarks>
 33    /// <example>
 34    /// Apply this editor to a string property like this:
 35    /// <code>
 36    /// [AutoCompleteSetup(AutoCompleteSource.FileSystem)]
 37    /// [Editor(typeof(AutoCompleteComboBoxEditor), typeof(UITypeEditor))]
 38    /// public string FilePath { get; set; }
 39    ///
 40    /// [AutoCompleteSetup(typeof(ConsoleColor))]
 41    /// [Editor(typeof(AutoCompleteComboBoxEditor), typeof(UITypeEditor))]
 42    /// public string FavoriteColor { get; set; }
 43    ///
 44    /// [AutoCompleteSetup("Red", "Green", "Blue")]
 45    /// [Editor(typeof(AutoCompleteComboBoxEditor), typeof(UITypeEditor))]
 46    /// public string CustomColor { get; set; }
 47    /// </code>
 48    /// </example>
 49    /// <seealso cref="DropDownVisualizer{T}"/>
 50    /// <seealso cref="AutoCompleteComboBox"/>
 51    /// <seealso cref="AutoCompleteSetupAttribute"/>
 52    public class AutoCompleteComboBoxEditor
 53        : DropDownVisualizer<AutoCompleteComboBox>
 54    {
 55        /// <summary>
 56        /// Gets or sets the <see cref="EnumConverter"/> used to convert between
 57        /// the displayed text in the combo box and the corresponding enum value.
 58        /// </summary>
 59        /// <remarks>
 60        /// This converter supports mapping from the display name to the actual enum constant,
 61        /// ensuring that the editor returns the correct enum value even when the display text differs.
 62        /// </remarks>
 63        public EnumConverter Converter
 64        {
 3265            get; set;
 66        }
 67
 68        /// <summary>
 69        /// Displays an <see cref="AutoCompleteComboBox"/> editor in a dropdown and returns the
 70        /// updated value after editing completes. Supports dynamic item lists and
 71        /// enum mapping when configured.
 72        /// </summary>
 73        /// <param name="context">Provides context information about the design-time environment.</param>
 74        /// <param name="provider">A service provider that can provide an <see cref="IWindowsFormsEditorService"/>.</par
 75        /// <param name="value">The current value of the property being edited.</param>
 76        /// <returns>
 77        /// The edited value as returned by the control. This is typically a string,
 78        /// but may be the corresponding enum value if the editor is configured with
 79        /// an enum type. If editing is canceled or fails, returns the original value.
 80        /// </returns>
 81        public override object EditValue(
 82            ITypeDescriptorContext context,
 83            IServiceProvider provider,
 84            object value)
 6485        {
 86            // Check for the attribute and apply the source before showing the dropdown
 7287            if (context?.PropertyDescriptor != null)
 6088            {
 6889                var sourceAttr = (AutoCompleteSetupAttribute)context.PropertyDescriptor.Attributes[typeof(AutoCompleteSe
 90
 6891                if (sourceAttr != null)
 5692                {
 6493                    ValidateSetup(sourceAttr, context);
 3294                    DropDownControl.AutoCompleteMode = sourceAttr.AutoCompleteMode;
 3295                    DropDownControl.AutoCompleteSource = sourceAttr.AutoCompleteSource;
 3296                    DropDownControl.DropDownStyle = sourceAttr.DropDownStyle;
 97
 3298                    if (sourceAttr.AutoCompleteSource == AutoCompleteSource.CustomSource)
 2499                    {
 32100                        DropDownControl.AutoCompleteCustomSource.Clear();
 32101                        DropDownControl.Items.Clear();
 102
 103                        object[] items;
 104
 32105                        var providerType = sourceAttr.ProviderType ?? context.PropertyDescriptor.PropertyType;
 106
 32107                        if (Converter != null && providerType.IsEnum)
 12108                        {
 109#if NET5_0_OR_GREATER
 4110                            items = [.. Enum.GetValues(providerType)
 4111                                .Cast<object>()
 12112                                .Select(e => new ItemWrapper<object>(
 12113                                    Converter.ConvertToString(context, CultureInfo.CurrentCulture, e), e))];
 114#else
 16115                            items = Enum.GetValues(providerType)
 16116                                .Cast<object>()
 16117                                .Select(e => new ItemWrapper<object>(
 16118                                    Converter.ConvertToString(context, CultureInfo.CurrentCulture, e), e))
 16119                                .ToArray();
 120#endif
 12121                        }
 122                        else
 28123                            items = ResolveValues(sourceAttr, context.PropertyDescriptor);
 124
 125#if NET5_0_OR_GREATER
 16126                        if (items[0] is ItemWrapper<object>)
 4127                            DropDownControl.AutoCompleteCustomSource.AddRange(
 12128                                [.. items.Cast<ItemWrapper<object>>().Select(i => i.DisplayText)]);
 129                        else
 12130                            DropDownControl.AutoCompleteCustomSource.AddRange(
 44131                                [.. items.Select(i => i.ToString())]);
 132#else
 16133                        if (items[0] is ItemWrapper<object>)
 16134                            DropDownControl.AutoCompleteCustomSource.AddRange(
 16135                                items.Cast<ItemWrapper<object>>().Select(i => i.DisplayText).ToArray());
 136                        else
 16137                            DropDownControl.AutoCompleteCustomSource.AddRange(
 16138                                items.Select(i => i.ToString()).ToArray());
 139#endif
 140
 32141                        DropDownControl.Items.AddRange(items);
 24142                    }
 24143                }
 28144            }
 145
 40146            return base.EditValue(context, provider, value);
 32147        }
 148
 149        /// <summary>
 150        /// Resolves the values.
 151        /// </summary>
 152        /// <param name="setup">The setup.</param>
 153        /// <param name="propDesc">The property desc.</param>
 154        /// <returns></returns>
 155        private static string[] ResolveValues(AutoCompleteSetupAttribute setup, PropertyDescriptor propDesc)
 20156        {
 157            // If the AutoCompleteSetupAttribute has Values set, use them directly
 28158            if (setup.Values?.Length > 0)
 20159                return setup.Values;
 160
 161            // If the ProviderType is set, try to get the static string[] Values property
 24162            var type = setup.ProviderType ?? propDesc.PropertyType;
 163
 24164            if (type.IsEnum)
 20165                return Enum.GetNames(type);
 166
 167            const string propName = "Values";
 20168            var prop = type.GetProperty(propName, BindingFlags.Public | BindingFlags.Static);
 169#if NET35
 170            return (string[])prop.GetValue(null, null);
 171#else
 20172            return (string[])prop.GetValue(null);
 173#endif
 20174        }
 175
 176        /// <summary>
 177        /// Validates the setup.
 178        /// </summary>
 179        /// <param name="setup">The setup.</param>
 180        /// <param name="context">The context.</param>
 181        /// <exception cref="ArgumentNullException">setup - AutoCompleteSetupAttribute must be assigned to the property 
 182        /// <exception cref="InvalidOperationException">
 183        /// At least one value must be specified when using AutoCompleteSourceMode.Values.
 184        /// or
 185        /// ProviderType could not be determined.
 186        /// or
 187        /// The enum '{providerType.Name}' does not define any members.
 188        /// or
 189        /// The type '{providerType.FullName}' must define a public static property named '{propName}'.
 190        /// or
 191        /// The '{propName}' property on '{providerType.FullName}' must be of type string[].
 192        /// or
 193        /// The '{propName}' property on '{providerType.FullName}' returned no items.
 194        /// </exception>
 195        private static void ValidateSetup(AutoCompleteSetupAttribute setup, ITypeDescriptorContext context)
 56196        {
 197            // If somehow setup is null, add the code in here to throw an exception.  Currently this routine
 198            // is called after a check to see if the setup is null, so this should never happen.
 64199            if (setup.AutoCompleteSource == AutoCompleteSource.CustomSource)
 64200                switch (setup.Mode)
 201                {
 202                    case AutoCompleteSetupAttribute.SourceMode.Values:
 28203                        if (setup.Values == null || setup.Values.Length == 0)
 24204                            throw new InvalidOperationException("At least one value must be specified when using AutoCom
 12205                        break;
 206
 207                    case AutoCompleteSetupAttribute.SourceMode.Provider:
 52208                        var providerType = setup.ProviderType ?? context.PropertyDescriptor.PropertyType;
 52209                        if (providerType.IsEnum)
 20210                        {
 28211                            var names = Enum.GetNames(providerType);
 28212                            if (names.Length == 0)
 20213                                throw new InvalidOperationException($"The enum '{providerType.Name}' does not define any
 16214                        }
 215                        else
 32216                        {
 217                            const string propName = "Values";
 40218                            var prop = providerType.GetProperty(propName, BindingFlags.Public | BindingFlags.Static)
 40219                                ?? throw new InvalidOperationException($"The type '{providerType.FullName}' must define 
 220
 36221                            if (prop.PropertyType != typeof(string[]))
 20222                                throw new InvalidOperationException($"The '{propName}' property on '{providerType.FullNa
 223
 224#if NET35
 225                            var values = (string[])prop.GetValue(null, null);
 226#else
 32227                            var values = (string[])prop.GetValue(null);
 228#endif
 32229                            if (values == null || values.Length == 0)
 28230                                throw new InvalidOperationException($"The '{propName}' property on '{providerType.FullNa
 12231                        }
 232
 20233                        break;
 234                }
 32235        }
 236    }
 237}

C:\Agent\_work\2\s\Code\PropertyGridHelpers\UIEditors\AutoCompleteComboBoxEditorT.cs

#LineLine coverage
 1using System.ComponentModel;
 2using System.Windows.Forms;
 3
 4namespace PropertyGridHelpers.UIEditors
 5{
 6    /// <summary>
 7    /// Provides a type-safe <see cref="AutoCompleteComboBoxEditor"/> for editing enum-based
 8    /// values in a <see cref="PropertyGrid"/>. This generic variant allows specifying a custom
 9    /// <see cref="EnumConverter"/> to control display and parsing behavior.
 10    /// </summary>
 11    /// <typeparam name="T">
 12    /// A custom <see cref="EnumConverter"/> type that provides conversion logic for the target enum.
 13    /// </typeparam>
 14    /// <remarks>
 15    /// This editor automatically creates an instance of <typeparamref name="T"/> and
 16    /// assigns it to the <see cref="AutoCompleteComboBoxEditor.Converter"/> property, allowing
 17    /// for customized enum text representation in the drop-down.
 18    /// </remarks>
 19    /// <seealso cref="AutoCompleteComboBoxEditor"/>
 20    public class AutoCompleteComboBoxEditor<T> : AutoCompleteComboBoxEditor
 21        where T : EnumConverter, new()
 22    {
 23        /// <summary>
 24        /// Initializes a new instance of the <see cref="AutoCompleteComboBoxEditor{T}"/> class.
 25        /// </summary>
 1626        public AutoCompleteComboBoxEditor() =>
 1627            Converter = new T();
 28    }
 29}