【问题标题】:Property grid item and DoubleClick属性网格项和 DoubleClick
【发布时间】:2011-01-22 16:22:16
【问题描述】:

我正在使用 PropertyGrid 控件来编辑我的应用程序中的一些对象。我正在使用自定义 TypeConverters 和 TypeEditors 以获得更好的用户界面。

我对布尔属性的自定义 TypeConverter 有疑问。如果我有这门课:

public class MyClass {
    public string Name { get; set; }

    [System.ComponentModel.TypeConverter( typeof( BoolTypeConverter ) )]
    public bool Flag { get; set; }
}

然后我创建实例并将其设置为 PropertyGrid 中的 SelectedObject - 一切都很好,直到用户双击属性网格项目表单“标志”属性。 DoubleClick 引发此消息后:
(来源:tcks.wz.cz)

TypeConverter 类看起来:

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;
    }
}

这种行为让用户非常困惑。如何预防?

谢谢

【问题讨论】:

    标签: c# .net winforms type-conversion propertygrid


    【解决方案1】:

    您的 GetStandardValues() 方法是错误的。它必须返回属性类型,而不是字符串:

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        StandardValuesCollection ret;
        Type tpProperty = context.PropertyDescriptor.PropertyType;
    
        if (tpProperty == typeof(bool))
            ret = new StandardValuesCollection(new object[] { true, false });
        else if (tpProperty == typeof(bool?))
            ret = new StandardValuesCollection(new object[] { true, false, null });
        else
            ret = new StandardValuesCollection(new object[0]);
    
        return ret;
    }
    

    【讨论】:

    • @Nicolas Cadilhac,谢谢!我花了多少小时寻找这个答案!
    • 大约 8,在我的情况下 >.>。我继承了一个相当复杂的通用 TypeConverter 来转换通用枚举,它有这个问题,而且我几乎不知道从哪里开始,因为从 PropertyGrid 处理转换主要是内部的 .net 魔法。终于找到了这篇文章,这正是我希望几小时前找到的。谢谢! (具体来说,它正在创建 [underlying object -> string] 的映射,然后 GetStandardValues 返回映射中的值而不是键。是的。)
    • 太棒了!正在开发一个枚举类型转换器,之前的开发人员正在返回一个字符串列表。现在我换成了一行 return ( new object[]{enum.enumvalue1, enum.enumvalue2}));它就像一个魅力。在进行此更改之前,我的属性网格中没有正确的双击行为(值没有变化)。
    猜你喜欢
    • 1970-01-01
    • 2013-04-06
    • 2010-12-12
    • 2011-05-21
    • 2023-03-09
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多