I am using the PropertyGrid control to edit some objects in my application. I use custom TypeConverters and TypeEditors for a better user interface.
I have a problem with a custom TypeConverter for boolean properties. If I have this class:
public class MyClass { public string Name { get; set; } [System.ComponentModel.TypeConverter( typeof( BoolTypeConverter ) )] public bool Flag { get; set; } }
and I create an instance and set it as SelectedObject in the PropertyGrid - everything is fine until the user double-clicks on the grid property element of the Flag property. After DoubleClick appears, this message: 
(source: tcks.wz.cz )
The TypeConverter class looks like this:
public class BoolTypeConverter : System.ComponentModel.TypeConverter { public const string TEXT_TRUE = "On"; public const string TEXT_FALSE = "Off"; public const string TEXT_NONE = "< none >"; public override object CreateInstance( System.ComponentModel.ITypeDescriptorContext context, System.Collections.IDictionary propertyValues ) { object ret = base.CreateInstance( context, propertyValues ); return ret; } public override bool GetCreateInstanceSupported( System.ComponentModel.ITypeDescriptorContext context ) { bool ret = base.GetCreateInstanceSupported( context ); return ret; } public override bool IsValid( System.ComponentModel.ITypeDescriptorContext context, object value ) { bool ret; if ( value is string ) { string tmpValue = value.ToString().Trim(); if ( string.Compare( tmpValue, TEXT_NONE, StringComparison.InvariantCultureIgnoreCase ) == 0 ) { ret = true; } else if ( string.Compare( tmpValue, TEXT_TRUE, StringComparison.InvariantCultureIgnoreCase ) == 0 ) { ret = true; } else if ( string.Compare( tmpValue, TEXT_FALSE, StringComparison.InvariantCultureIgnoreCase ) == 0 ) { ret = true; } else { bool blValue; ret = bool.TryParse( tmpValue, out blValue ); } } else { ret = base.IsValid( context, value ); } return ret; } public override bool CanConvertFrom( System.ComponentModel.ITypeDescriptorContext context, Type sourceType ) { bool ret = false; if ( sourceType == typeof( string ) ) { ret = true; } else { ret = base.CanConvertFrom( context, sourceType ); } return ret; } public override object ConvertFrom( System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value ) { object ret = null; bool converted = false; if ( value is string ) { string tmpValue = value.ToString().Trim(); if ( string.Compare( tmpValue, TEXT_NONE, StringComparison.InvariantCultureIgnoreCase ) == 0 || string.IsNullOrEmpty( tmpValue ) ) { ret = null; converted = true; } else if ( string.Compare( tmpValue, TEXT_TRUE, StringComparison.InvariantCultureIgnoreCase ) == 0 ) { ret = true; converted = true; } else if ( string.Compare( tmpValue, TEXT_FALSE, StringComparison.InvariantCultureIgnoreCase ) == 0 ) { ret = false; converted = true; } else { bool blValue; if ( converted = bool.TryParse( tmpValue, out blValue ) ) { ret = blValue; } } } if ( false == converted ) { ret = base.ConvertFrom( context, culture, value ); } return ret; } public override bool CanConvertTo( System.ComponentModel.ITypeDescriptorContext context, Type destinationType ) { bool ret = false; if ( destinationType == typeof( bool ) ) { ret = true; } else { ret = base.CanConvertTo( context, destinationType ); } return ret; } public override object ConvertTo( System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType ) { object ret = null; bool converted = false; if ( destinationType == typeof( string ) ) { if ( null == value ) { ret = TEXT_NONE; converted = true; } else if ( value is bool? || value is bool ) { if ( (bool)value ) { ret = TEXT_TRUE; } else { ret = TEXT_FALSE; } converted = true; } else if ( value is string ) { ret = value; converted = true; } } if ( false == converted ) { ret = base.ConvertTo( context, culture, value, destinationType ); } return ret; } public override StandardValuesCollection GetStandardValues( System.ComponentModel.ITypeDescriptorContext context ) { StandardValuesCollection ret; Type tpProperty = context.PropertyDescriptor.PropertyType; if ( tpProperty == typeof( bool ) ) { ret = new StandardValuesCollection( new string[]{ TEXT_TRUE, TEXT_FALSE } ); } else if ( tpProperty == typeof( bool? ) ) { ret = new StandardValuesCollection( new string[]{ TEXT_TRUE, TEXT_FALSE, TEXT_NONE } ); } else { ret = new StandardValuesCollection( new string[0] ); } return ret; } public override bool GetStandardValuesSupported( System.ComponentModel.ITypeDescriptorContext context ) { bool ret; Type tpProperty = context.PropertyDescriptor.PropertyType; if ( tpProperty == typeof( bool ) || tpProperty == typeof( bool? ) ) { ret = true; } else { ret = false; } return ret; } }
This behavior is very confusing for users. How can I prevent this?
thanks