在Windows窗体的属性网格中正确显示自定义对象列表

时间:2015-06-16 21:53:14

标签: c# winforms propertygrid typeconverter

我正在尝试在属性网格中显示我的Wall类的属性。现在我的墙类看起来像这样:

[TypeConverter(typeof(ExpandableObjectConverter))]
public class WallType
{
    #region _private variables and Properties
    public string Name { get; set; } //Name of the wall to identify it. For the wall program, it is automatically generated (ex. E4-1 where E = exterior wall, 4 = 2x4, and 1 means first exterior wall defined)
    public string Type { get; set; } //Type of wall (exterior, interior, etc.)
    public bool IsMirrorable { get; set; } //Identifies if the wall is mirrorable or not
    public Distance Height { get; set; } //Height of the wall from bottom to talk
    public string StudPattern { get; set; } //Pattern in which the studs of the wall are laid out
    public Distance StudSpacing { get; set; } //Spacing between each stud
    public VaporBarrier Barrier { get; set; }
    public LetIn LetInOfWall { get; set; }
    public Sheathing SheathingUsed { get; set; }
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public List<Member> Members { get; set; }
    public bool HasLetIn { get; set; }
    public bool HasCapPlate { get; set; }
    public bool HasVaporBarrier { get; set; }
    public bool HasSheathing { get; set; }
    #endregion

    /*Constructors and Methods not shown*/
 }

当我在属性网格上显示一个WallType实例时,它会出现如下:

enter image description here

除了会员财产外,一切看起来都不错。现在它只是显示容量和数量。我想要的是它显示列表中每个成员的名称属性。我认为在列表上放置一个ExpandableObjectConverter可以解决问题,但它没有。所以我尝试将自定义TypeConverter放在Member类

之上
[TypeConverter(typeof(MemberObjectConverter))]
public class Member
{
    #region _private variables and Properties
    public string Name { get; set; } //Name of the member used to uniquely identify it
    public string Size { get; set; } //Size of the member (ex. 2x4)
    public string Grade { get; set; } //Grade of the wood used to make the member
    public Distance Length { get; set; } //Length of the member
    public string Species { get; set; } //Type of wood the member is made of
    public string Treatment { get; set; } //Type of treatment applied to the member
    public string Other { get; set; } //Variable for other notes about the member
    #endregion
    /*Constructors and Methods not shown*/
}

最后,我的自定义类型转换器

namespace Wall_Program
{
    /// <summary>
    /// Extending the ExpandableObjectConverter to display member objects properly
    /// </summary>
    public class MemberObjectConverter : ExpandableObjectConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(Member))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, System.Type destinationType)
        {
            if (destinationType == typeof(System.String) && value is Member)
            {
                Member m = (Member)value;
                return "Name: " + m.Name +
                    ", Size: " + m.Size +
                    ", Grade: " + m.Grade +
                    ", Length: " + m.Length.Architectural +
                    ", Species: " + m.Species +
                    ", Treatment: " + m.Treatment +
                    ", Other: " + m.Other;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is string)
            {
                try
                {
                    string s = (string)value;
                    int colon = s.IndexOf(':');
                    int comma = s.IndexOf(',');

                    if (colon != -1 && comma != -1)
                    {
                        string name = s.Substring(colon + 1, (comma - colon - 1));

                        colon = s.IndexOf(':', comma + 1);
                        comma = s.IndexOf(',', comma + 1);
                        string size = s.Substring(colon + 1, (comma - colon - 1));

                        colon = s.IndexOf(':', comma + 1);
                        comma = s.IndexOf(',', comma + 1);
                        string grade = s.Substring(colon + 1);

                        colon = s.IndexOf(':', comma + 1);
                        comma = s.IndexOf(',', comma + 1);
                        Distance length = new Distance(s.Substring(colon + 1, (comma - colon - 1)));

                        colon = s.IndexOf(':', comma + 1);
                        comma = s.IndexOf(',', comma + 1);
                        string species = s.Substring(colon + 1, (comma - colon - 1));

                        colon = s.IndexOf(':', comma + 1);
                        comma = s.IndexOf(',', comma + 1);
                        string treatment = s.Substring(colon + 1, (comma - colon - 1));

                        colon = s.IndexOf(':', comma + 1);
                        string other = s.Substring(colon + 1);

                        Member m = new Member(name, size, grade, length, species, treatment, other);
                        return m;
                    }
                }
                catch
                {
                    throw new ArgumentException("Can not convert '" + (string)value + "' to type Member");
                }
            }
            return base.ConvertFrom(context, culture, value);
        }
    }
}

自定义类型转换器有一些效果,因为当我单击按钮手动显示集合时,所有内容都已正确列出。但我想要的是名字是显示的而不是容量和数量。

enter image description here

1 个答案:

答案 0 :(得分:1)

这是相当不寻常的,因为Plutonix评论说,但这是一种方法。

只需在Members属性上使用以下TypeConverter即可。由于PropertyGrid基于属性,因此您必须创建表示每个成员的虚假属性。这就是代表MemberDescriptor类的内容。

public class MyTypeConverter : TypeConverter
{
    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType != typeof(string))
            return base.ConvertTo(context, culture, value, destinationType);

        List<Member> members = value as List<Member>;
        if (members == null)
            return "-";

        return string.Join(", ", members.Select(m => m.Name));
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        List<PropertyDescriptor> list = new List<PropertyDescriptor>();
        List<Member> members = value as List<Member>;
        if (members != null)
        {
            foreach (Member member in members)
            {
                if (member.Name != null)
                {
                    list.Add(new MemberDescriptor(member, list.Count));
                }
            }
        }
        return new PropertyDescriptorCollection(list.ToArray());
    }

    private class MemberDescriptor : SimplePropertyDescriptor
    {
        public MemberDescriptor(Member member, int index)
            : base(member.GetType(), index.ToString(), typeof(string))
        {
            Member = member;
        }

        public Member Member { get; private set; }

        public override object GetValue(object component)
        {
            return Member.Name;
        }

        public override void SetValue(object component, object value)
        {
            Member.Name = (string)value;
        }
    }
}

作为奖励,我还将转换添加到字符串中,因此它看起来更好:

enter image description here