属性网格中属性“名称”的特殊含义

时间:2014-02-13 09:47:01

标签: c# .net winforms propertygrid

  • 我使用PropertyGrid来允许最终用户编辑类ClassA
  • 中的属性
  • 此类具有List<ClassB>属性。
  • 对于List<ClassB>属性,PropertyGrid会显示(Collection)和一个带有3个点的按钮,这会打开一个看起来像这样的新窗口(取自another SO post)。

enter image description here

  • 我想自定义左侧的Members: DisplayName,因此ClassB我已覆盖ToString()方法

    public class ClassB
    {
        public string Name { get; set; }
        public TimeSpan Value { get; set; }
    
        public override ToString() { return String.Format("{0} ({1})", this.Name, this.Value); }
    }
    

现在出现了问题:

  • 如果名称为空,则会按预期显示(00:00:00)
  • 如果我将名称更改为“测试”,我希望它显示为Test (00:00:00),但它只显示Test
  • 如果我将属性Name重命名为其他名称,则按预期工作。

我认为这是一个特殊的约定,如果一个类有一个属性Name并且该值不为null或为空,则控件显示此属性而不是名称。

但是,我还没有找到一个验证该文档的文档,而且我不知道如何更改此行为。我该怎么做?

注意:不能更改属性名称。

1 个答案:

答案 0 :(得分:2)

不幸的是,CollectionEditor.GetDisplayText Method中的逻辑非常硬编码。它没有记录,但您可以使用工具对其进行反汇编。这是代码:

protected virtual string GetDisplayText(object value)
{
    string str;
    if (value == null)
        return string.Empty;

    // use the Name property
    PropertyDescriptor defaultProperty = TypeDescriptor.GetProperties(value)["Name"];
    if ((defaultProperty != null) && (defaultProperty.PropertyType == typeof(string)))
    {
        str = (string) defaultProperty.GetValue(value);
        if ((str != null) && (str.Length > 0))
        {
            return str;
        }
    }

    // or use the DefaultPropertyAttribute
    defaultProperty = TypeDescriptor.GetDefaultProperty(this.CollectionType);
    if ((defaultProperty != null) && (defaultProperty.PropertyType == typeof(string)))
    {
        str = (string) defaultProperty.GetValue(value);
        if ((str != null) && (str.Length > 0))
        {
            return str;
        }
    }

    // or use the TypeConverter
    str = TypeDescriptor.GetConverter(value).ConvertToString(value);
    if ((str != null) && (str.Length != 0))
    {
        return str;
    }

    // or use the type name
    return value.GetType().Name;
}

这段代码非常讨厌,因为它基本上反过来做事情。它应该使用Name属性作为最后的手段,而不是专注于它......

但是由于CollectionEditor类没有被密封,所以希望不会丢失。这是你如何解决它:

1)在持有集合的类上声明EditorAttribute,如下所示:

public class ClassA
{
    [Editor(typeof(MyCollectionEditor), typeof(UITypeEditor))]
    public List<ClassB> List { get; set; }
}

2)定义你的自定义集合编辑器,像这样;

public class MyCollectionEditor : CollectionEditor // needs a reference to System.Design
{
    public MyCollectionEditor(Type type)
        : base(type)
    {
    }

    protected override string GetDisplayText(object value)
    {
        // force ToString() usage, but
        // you also could implement some custom logic here
        return string.Format("{0}", value);
    }
}