< Summary - PropertyGridHelpers Code Coverage

Information
Class: PropertyGridHelpers.Converters.OnlySelectableTypeConverter
Assembly: PropertyGridHelpers
File(s): c:\agent\_work\9\s\Code\PropertyGridHelpers\Converters\OnlySelectableTypeConverter.cs
Tag: PropertyGridHelpers Build_2025.7.15.1_#485
Line coverage
100%
Covered lines: 34
Uncovered lines: 0
Coverable lines: 34
Total lines: 126
Line coverage: 100%
Branch coverage
100%
Covered branches: 20
Total branches: 20
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBlocks covered Blocks not covered Branch coverage Crap Score Cyclomatic complexity Line coverage
ConvertFrom(...)180----
ConvertFrom(...)--100%88100%
ConvertFrom(...)140----
GetStandardValuesSupported(...)10100%11100%
GetStandardValuesExclusive(...)10100%11100%
GetStandardValues(...)400100%1212100%
GetStandardValues(...)380----

File(s)

c:\agent\_work\9\s\Code\PropertyGridHelpers\Converters\OnlySelectableTypeConverter.cs

#LineLine coverage
 1using PropertyGridHelpers.Attributes;
 2using PropertyGridHelpers.UIEditors;
 3using System;
 4using System.Collections.Generic;
 5using System.ComponentModel;
 6using System.Globalization;
 7using System.Linq;
 8
 9namespace PropertyGridHelpers.Converters
 10{
 11    /// <summary>
 12    /// Provides a type converter that restricts input to selectable values only.
 13    /// </summary>
 14    /// <remarks>
 15    /// This converter is used with the <see cref="ResourcePathEditor" /> to
 16    /// prevent users from manually editing text in the PropertyGrid, while still
 17    /// allowing selection from a predefined dropdown list.
 18    /// </remarks>
 19    /// <example>
 20    /// <code language="csharp">
 21    /// [AllowBlank(includeItem: true, resourceItem: "Blank_ResourcePath")]
 22    /// [LocalizedCategory("Category_TestItems")]
 23    /// [LocalizedDescription("Description_ResourcePath")]
 24    /// [LocalizedDisplayName("DisplayName_ResourcePath")]
 25    /// [Editor(typeof(ResourcePathEditor), typeof(UITypeEditor))]
 26    /// [TypeConverter(typeof(OnlySelectableTypeConverter))]
 27    /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 28    /// public string ResourcePath { get; set; }
 29    /// </code>
 30    /// </example>
 31    /// <seealso cref="StringConverter" />
 32    /// <seealso cref="AllowBlankAttribute"/>
 33    /// <seealso cref="ResourcePathEditor"/>
 34    public class OnlySelectableTypeConverter : StringConverter
 35    {
 36        /// <summary>
 37        /// Converts from a string to a element in an Enum.
 38        /// </summary>
 39        /// <param name="context">Context information from the property grid.</param>
 40        /// <param name="culture">Culture info to use for parsing.</param>
 41        /// <param name="value">The string to convert from.</param>
 42        /// <returns></returns>
 43        /// <exception cref="ArgumentException">Value cannot be blank and no valid options are available.</exception>
 44        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 2845        {
 46            // If the incoming value is an empty string, or just white space
 47#if NET35
 48            if (value is string str && string.IsNullOrEmpty(str))
 49#else
 3650            if (value is string str && string.IsNullOrWhiteSpace(str))
 51#endif
 2052            {
 53                // check to see if blanks are allowed or not
 2854                if (!AllowBlankAttribute.IsBlankAllowed(context))
 1655                {
 56                    // If blank is not allowed, then we need to return the name of the first resource path
 2457                    var first = GetStandardValues(context).Cast<string>().FirstOrDefault();
 58                    // If we have a resource path, return it, or throw an error if there are no resource paths available
 2459                    return first != null ? (object)first : throw new ArgumentException("Value cannot be blank and no val
 60                }
 1261            }
 62
 2863            return base.ConvertFrom(context, culture, value);
 2064        }
 65
 66        /// <inheritdoc/>
 2067        public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;
 68
 69        /// <inheritdoc/>
 2070        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) => true;
 71
 72        /// <summary>
 73        /// Returns a list of resource paths found in the current instance’s assembly,
 74        /// suitable for selection in a property grid editor or a dropdown.
 75        /// </summary>
 76        /// <param name="context">
 77        /// Provides contextual information, including the instance whose assembly will be inspected.
 78        /// </param>
 79        /// <returns>
 80        /// A <see cref="TypeConverter.StandardValuesCollection"/> containing the names of resources
 81        /// (without the assembly prefix and without the <c>.resources</c> extension) that are embedded
 82        /// in the same assembly as the edited object. If no assembly is available in the context, an
 83        /// empty collection is returned.
 84        /// </returns>
 85        /// <remarks>
 86        /// This is used to present a list of available resource names (for example, localization resources or
 87        /// embedded files) that a user might select from in the property grid.
 88        /// </remarks>
 89
 90        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
 2491        {
 3292            var assembly = context?.Instance?.GetType().Assembly;
 3293            if (assembly == null)
 94#if NET8_0_OR_GREATER || NET462_OR_GREATER
 2095                return new StandardValuesCollection(Array.Empty<string>());
 96#else
 497                return new StandardValuesCollection(new string[0]);
 98#endif
 99
 24100            var resources = assembly.GetManifestResourceNames();
 24101            var list = new List<string>();
 24102            var prefix = $"{assembly.GetName().Name}.";
 103
 104104            foreach (var res in resources)
 40105            {
 48106                if (res.EndsWith(".resources", StringComparison.InvariantCultureIgnoreCase))
 32107                {
 108#if NET8_0_OR_GREATER
 24109                    var name = res[..^".resources".Length];
 110#else
 16111                    var name = res.Substring(0, res.Length - ".resources".Length);
 112#endif
 40113                    if (name.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
 114#if NET8_0_OR_GREATER
 24115                        name = name[prefix.Length..];
 116#else
 16117                        name = name.Substring(prefix.Length);
 118#endif
 40119                    list.Add(name);
 32120                }
 40121            }
 122
 48123            return new StandardValuesCollection(list.OrderBy(s => s).ToArray());
 24124        }
 125    }
 126}