Search code examples
.netwinformspropertygrid

Winforms PropertyGrid: how do I allow free form text, and a modal dialog for editing a property?


I have a form developed in Winforms and using the PropertyGrid to allow users to edit data. I have figured out how to define custom type editors for properties that need more than the built in functionality of the property grid and this is all working successfully. I have one String property though whose type editor opens a modal dialog and allows them to edit the string through a form that I have defined, but this particular property when it is simple could also be just entered into the property grid as free form text.

So I'd like to still show the ellipsis button in the property grid so that they can edit through the dialog, but also I want the cell in the property grid to allow free form text. There must be a way to do this as the Font type's editor allows for this, but I have not found the solution. Does anybody have any idea how to do this? Thanks You.


Solution

  • You can use a TypeConverter that supports string conversion for this. For example, here is a TypeConverter for a property of Encoding type, that would be declared like this:

    public class MyClass
    {
        ...
        [TypeConverter(typeof(EncodingConverter))]
        public Encoding MyEncoding { get; set; }
        ...
    }
    
    /// <summary>
    /// Provides a type converter to convert Encoding objects to and from various other representations.
    /// </summary>
    public class EncodingConverter: TypeConverter
    {
        /// <summary>
        /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="sourceType">A <see cref="T:System.Type"/> that represents the type you want to convert from.</param>
        /// <returns>
        /// true if this converter can perform the conversion; otherwise, false.
        /// </returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return ((typeof(string) == sourceType) || base.CanConvertFrom(context, sourceType));
        }
    
        /// <summary>
        /// Returns whether this converter can convert the object to the specified type, using the specified context.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="destinationType">A <see cref="T:System.Type"/> that represents the type you want to convert to.</param>
        /// <returns>
        /// true if this converter can perform the conversion; otherwise, false.
        /// </returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return ((typeof(string) == destinationType) || base.CanConvertTo(context, destinationType));
        }
    
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">
        /// The conversion cannot be performed.
        /// </exception>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (!(value is string))
                return base.ConvertFrom(context, culture, value);
    
            string name = (string)value;
            if (name == null)
                return null;
    
            return Encoding.GetEncoding(name);
        }
    
        /// <summary>
        /// Converts the given value object to the specified type, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">A <see cref="T:System.Globalization.CultureInfo"/>. If null is passed, the current culture is assumed.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <param name="destinationType">The <see cref="T:System.Type"/> to convert the <paramref name="value"/> parameter to.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// The <paramref name="destinationType"/> parameter is null.
        /// </exception>
        /// <exception cref="T:System.NotSupportedException">
        /// The conversion cannot be performed.
        /// </exception>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if ((typeof(string) == destinationType) && (value is Encoding))
            {
                Encoding encoding = (Encoding)value;
                return encoding.HeaderName;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }