PropertyGrid 如何添加可编辑列表

发布于 2024-12-04 13:23:50 字数 263 浏览 1 评论 0原文

我有一个具有 IList 属性的类 MyClassA。我正在使用 PropertyGrid 控件来显示 MyClassA 的所有属性,并且我希望通过 MyClassA 的 PropertyGrid 显示和编辑 MyClassB 的列表。

目前,除了 MyClassB 列表的属性之外,所有其他属性都显示在属性网格中。如何将 MyClassB 列表添加到属性网格,用户可以在其中添加/编辑/删除列表中的项目?

尽管我仍在挖掘,但到目前为止,我还没有真正找到任何详细说明这一点的示例。

I have a class MyClassA that has an IList property. I am using a PropertyGrid control to display all the properties of MyClassA and I would like the list of MyClassB to be displayed and editable via the PropertyGrid for MyClassA.

I currently have all the other properties being displayed in the Property grid except for the property that is the list of MyClassB. How do I go about adding the List of MyClassB to the property grid where the user can add/edit/remove items from the List?

I haven't really been able to find any examples that go into detail on this as of yet although I am still digging.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笔芯 2024-12-11 13:23:50

这是我到目前为止已经制定出的解决方案,尽管它仍然不能 100% 符合我正在寻找的内容。

我发现可以根据自己的喜好修改此参考: http://www.codeproject.com/KB /tabs/customizingcollectiondata.aspx

我所做的是创建一个继承自 CollectionBase 并使用 ICustomTypeDescriptor 的新类。

完成此操作并实现基本功能后,我必须为该类创建一个 PropertyDescriptor。

代码如下:

public class ZoneCollection : CollectionBase, ICustomTypeDescriptor
{
    #region Collection Implementation

    /// <summary>
    /// Adds an zone object to the collection
    /// </summary>
    /// <param name="emp"></param>
    public void Add(Zone zone)
    {
        this.List.Add(zone);
    }

    /// <summary>
    /// Removes an zone object from the collection
    /// </summary>
    /// <param name="emp"></param>
    public void Remove(Zone zone)
    {
        this.List.Remove(zone);
    }

    /// <summary>
    /// Returns an zone object at index position.
    /// </summary>
    public Zone this[int index]
    {
        get
        {
            return (Zone)this.List[index];
        }
    }

    #endregion

    // Implementation of interface ICustomTypeDescriptor 
    #region ICustomTypeDescriptor impl

    public String GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    public AttributeCollection GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    public String GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }

    public TypeConverter GetConverter()
    {
        return TypeDescriptor.GetConverter(this, true);
    }

    public EventDescriptor GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(this, true);
    }

    public PropertyDescriptor GetDefaultProperty()
    {
        return TypeDescriptor.GetDefaultProperty(this, true);
    }

    public object GetEditor(Type editorBaseType)
    {
        return TypeDescriptor.GetEditor(this, editorBaseType, true);
    }

    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }

    public EventDescriptorCollection GetEvents()
    {
        return TypeDescriptor.GetEvents(this, true);
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }


    /// <summary>
    /// Called to get the properties of this type. Returns properties with certain
    /// attributes. this restriction is not implemented here.
    /// </summary>
    /// <param name="attributes"></param>
    /// <returns></returns>
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return GetProperties();
    }

    /// <summary>
    /// Called to get the properties of this type.
    /// </summary>
    /// <returns></returns>
    public PropertyDescriptorCollection GetProperties()
    {
        // Create a collection object to hold property descriptors
        PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);

        // Iterate the list of employees
        for (int i = 0; i < this.List.Count; i++)
        {
            // Create a property descriptor for the zone item and add to the property descriptor collection
            ZoneCollectionPropertyDescriptor pd = new ZoneCollectionPropertyDescriptor(this, i);
            pds.Add(pd);
        }
        // return the property descriptor collection
        return pds;
    }

    #endregion
}

/// <summary>
/// Summary description for CollectionPropertyDescriptor.
/// </summary>
public class ZoneCollectionPropertyDescriptor : PropertyDescriptor
{
    private ZoneCollection collection = null;
    private int index = -1;

    public ZoneCollectionPropertyDescriptor(ZoneCollection coll, int idx) :
        base("#" + idx.ToString(), null)
    {
        this.collection = coll;
        this.index = idx;
    }

    public override AttributeCollection Attributes
    {
        get
        {
            return new AttributeCollection(null);
        }
    }

    public override bool CanResetValue(object component)
    {
        return true;
    }

    public override Type ComponentType
    {
        get
        {
            return this.collection.GetType();
        }
    }

    public override string DisplayName
    {
        get
        {
            Zone zone = this.collection[index];
            return zone.ID.ToString();
        }
    }

    public override string Description
    {
        get
        {
            Zone zone = this.collection[index];
            StringBuilder sb = new StringBuilder();
            sb.Append(zone.ID.ToString());

            if ( zone.Streets.Route != String.Empty || zone.Streets.Crossing != String.Empty)
                sb.Append("::");
            if (zone.Streets.Route != String.Empty)
                sb.Append(zone.Streets.Route);
            if ( zone.Streets.Crossing != String.Empty)
            {
                sb.Append(" and ");
                sb.Append(zone.Streets.Crossing);
            }

            return sb.ToString();
        }
    }

    public override object GetValue(object component)
    {
        return this.collection[index];
    }

    public override bool IsReadOnly
    {
        get { return false; }
    }

    public override string Name
    {
        get { return "#" + index.ToString(); }
    }

    public override Type PropertyType
    {
        get { return this.collection[index].GetType(); }
    }

    public override void ResetValue(object component)
    {
    }

    public override bool ShouldSerializeValue(object component)
    {
        return true;
    }

    public override void SetValue(object component, object value)
    {
        // this.collection[index] = value;
    }
}

Intersection 现在包含 ZoneCollection 而不是 IList,我现在可以编辑/添加/删除集合中包含的区域。

现在,如果我能让这个更通用,我会相对高兴。我的模型的另一个障碍是我必须使用它而不是 IList 从 Collection 基继承。这完全破坏了我对 NHibernate 类的映射,我现在必须尝试找出如何使用上述方法重新映射此列表。

如果有人想进一步详细说明这一点,我将不胜感激更多的见解。

Here is a solution I have worked out so far, although it still doesn't fit in 100% to what I am looking for.

I found this reference to modify for my liking: http://www.codeproject.com/KB/tabs/customizingcollectiondata.aspx

What I did was create a new class that inherits from CollectionBase and that uses an ICustomTypeDescriptor.

After I did this and implemented the basic functionality, I had to create a PropertyDescriptor for the class.

Here is the code:

public class ZoneCollection : CollectionBase, ICustomTypeDescriptor
{
    #region Collection Implementation

    /// <summary>
    /// Adds an zone object to the collection
    /// </summary>
    /// <param name="emp"></param>
    public void Add(Zone zone)
    {
        this.List.Add(zone);
    }

    /// <summary>
    /// Removes an zone object from the collection
    /// </summary>
    /// <param name="emp"></param>
    public void Remove(Zone zone)
    {
        this.List.Remove(zone);
    }

    /// <summary>
    /// Returns an zone object at index position.
    /// </summary>
    public Zone this[int index]
    {
        get
        {
            return (Zone)this.List[index];
        }
    }

    #endregion

    // Implementation of interface ICustomTypeDescriptor 
    #region ICustomTypeDescriptor impl

    public String GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    public AttributeCollection GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    public String GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }

    public TypeConverter GetConverter()
    {
        return TypeDescriptor.GetConverter(this, true);
    }

    public EventDescriptor GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(this, true);
    }

    public PropertyDescriptor GetDefaultProperty()
    {
        return TypeDescriptor.GetDefaultProperty(this, true);
    }

    public object GetEditor(Type editorBaseType)
    {
        return TypeDescriptor.GetEditor(this, editorBaseType, true);
    }

    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }

    public EventDescriptorCollection GetEvents()
    {
        return TypeDescriptor.GetEvents(this, true);
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }


    /// <summary>
    /// Called to get the properties of this type. Returns properties with certain
    /// attributes. this restriction is not implemented here.
    /// </summary>
    /// <param name="attributes"></param>
    /// <returns></returns>
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return GetProperties();
    }

    /// <summary>
    /// Called to get the properties of this type.
    /// </summary>
    /// <returns></returns>
    public PropertyDescriptorCollection GetProperties()
    {
        // Create a collection object to hold property descriptors
        PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);

        // Iterate the list of employees
        for (int i = 0; i < this.List.Count; i++)
        {
            // Create a property descriptor for the zone item and add to the property descriptor collection
            ZoneCollectionPropertyDescriptor pd = new ZoneCollectionPropertyDescriptor(this, i);
            pds.Add(pd);
        }
        // return the property descriptor collection
        return pds;
    }

    #endregion
}

/// <summary>
/// Summary description for CollectionPropertyDescriptor.
/// </summary>
public class ZoneCollectionPropertyDescriptor : PropertyDescriptor
{
    private ZoneCollection collection = null;
    private int index = -1;

    public ZoneCollectionPropertyDescriptor(ZoneCollection coll, int idx) :
        base("#" + idx.ToString(), null)
    {
        this.collection = coll;
        this.index = idx;
    }

    public override AttributeCollection Attributes
    {
        get
        {
            return new AttributeCollection(null);
        }
    }

    public override bool CanResetValue(object component)
    {
        return true;
    }

    public override Type ComponentType
    {
        get
        {
            return this.collection.GetType();
        }
    }

    public override string DisplayName
    {
        get
        {
            Zone zone = this.collection[index];
            return zone.ID.ToString();
        }
    }

    public override string Description
    {
        get
        {
            Zone zone = this.collection[index];
            StringBuilder sb = new StringBuilder();
            sb.Append(zone.ID.ToString());

            if ( zone.Streets.Route != String.Empty || zone.Streets.Crossing != String.Empty)
                sb.Append("::");
            if (zone.Streets.Route != String.Empty)
                sb.Append(zone.Streets.Route);
            if ( zone.Streets.Crossing != String.Empty)
            {
                sb.Append(" and ");
                sb.Append(zone.Streets.Crossing);
            }

            return sb.ToString();
        }
    }

    public override object GetValue(object component)
    {
        return this.collection[index];
    }

    public override bool IsReadOnly
    {
        get { return false; }
    }

    public override string Name
    {
        get { return "#" + index.ToString(); }
    }

    public override Type PropertyType
    {
        get { return this.collection[index].GetType(); }
    }

    public override void ResetValue(object component)
    {
    }

    public override bool ShouldSerializeValue(object component)
    {
        return true;
    }

    public override void SetValue(object component, object value)
    {
        // this.collection[index] = value;
    }
}

Intersection now contains a ZoneCollection instead of an IList and I can now edit/add/remove the zones contained within the collection.

Now, if I could make this more generic I'd be relatively happy. Another hindrance for my model is that I had to inherit from Collection base using this, instead of IList. This completely broke my mapping of my class for NHibernate and I'm now having to try and figure out how to remap this list using the method mentioned above.

If anyone wants to elaborate this any further I'd greatly appreciate some more insight.

篱下浅笙歌 2024-12-11 13:23:50

我知道这个主题已有 2 年多了,但也许您可能会感兴趣。

我有一个类似的问题。
首先:我需要 3D 空间中的一个点,该点应该可以在属性网格中进行配置
为此我创建了一个 Koord 类。为了使其在 PropertyGrid 中可更改,我创建了一个新类“KoordConverter : TypeConverter”
这是在 Vexel 中使用的(查看维基百科以了解它的用途:-))

为了创建 TestBock(某些 3D 对象),我使用了 Vexels 列表。
不幸的是,我的程序中需要一个测试块列表,可以通过属性网格看到。

从最上面开始:

public partial class FormMain : Form
{
    private BlockProperties _bp = new BlockProperties();

    public FormMain()
    {
        InitializeComponent();
        pgProperties.SelectedObject = _bp;
    }
[...]
}

BlockProperties 类包括 TestBocks 列表,我填充了一些内容以向您展示里面的内容。

class BlockProperties
{
    public List<TestBocks> Testing { get; set; }

    public BlockProperties()
    {
        Testing = new List<TestBocks>(3);

        List<Vexel> t1 = new List<Vexel>(1);
        t1.Add(new Vexel(new Koord(1,0,1), 1));

        List<Vexel> t2 = new List<Vexel>(2);
        t2.Add(new Vexel(new Koord(2, 0, 1), 2));
        t2.Add(new Vexel(new Koord(2, 0, 2), 2));

        List<Vexel> t3 = new List<Vexel>(3);
        t3.Add(new Vexel(new Koord(3, 0, 1), 3));
        t3.Add(new Vexel(new Koord(3, 0, 2), 3));
        t3.Add(new Vexel(new Koord(3, 0, 3), 3));

        TestBocks tb1 = new TestBocks();
        tb1.Koords = t1;

        TestBocks tb2 = new TestBocks();
        tb2.Koords = t2;

        TestBocks tb3 = new TestBocks();
        tb3.Koords = t3;

        Testing.Add(tb1);
        Testing.Add(tb2);
        Testing.Add(tb3);
    [...]
    }
[...]
}

接下来是我的 TestBlock 类,它非常简单

[Serializable]
public class TestBocks
{
    public List<Vexel> Vexels{ get; set; }
    public TestBocks()
    {
        Vexels = new List<Vexel>();
    }
}

在 Vexels 中是我的程序所需的大部分魔力:
我什至在这里放置了一个 ToString() 以方便调试。

public class Vexel
{
    private Koord _origin;
    private double _extent;

    public Koord Origin { get { return _origin; }  set { _origin = value; } }

    public double Extent { get { return _extent; } set { _extent = value; } }

    public string ToString()
    {
        NumberFormatInfo nFormatInfo = new NumberFormatInfo
        {
            NumberDecimalSeparator = ".",
            NumberGroupSeparator = ""
        }; 
        return String.Format(nFormatInfo, "Origin;{0};{1};{2};Extent;{3}", _origin.X, _origin.Y, _origin.Z, _extent);
    }

    public Vexel()
    {
        _origin = new Koord(0,0,0);
        Extent = 0;
    }

    public Vexel(Koord origin, double extent)
    {
        //TODO do some checking
        _origin = origin;
        _extent = extent;
    }

到目前为止,PropertyGrid 一切正常,但我无法编辑 Koords。
该类非常简单,但在 PropertyGrid 中不可编辑。
添加 TypeConverterClass 解决了这个问题(您可以在 Koord 代码下面找到 TypeConverter)

[TypeConverter(typeof(KoordConverter))]
[Serializable]
public class Koord
{
    private double p_1;
    private double p_2;
    private double p_3;

    public Koord(double x, double y, double z)
    {
        this.p_1 = x;
        this.p_2 = y;
        this.p_3 = z;
    }

    public string ToString()
    {
        return String.Format("X;{0};Y;{1};Z;{2}", p_1, p_2, p_3);
    }

    public double X { get { return p_1; } }
    public double Y { get { return p_2; } }
    public double Z { get { return p_3; } }
}

Typeconverter 是编写最复杂的代码。您可以在下面找到它:

public class KoordConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        string text = value as string;
        if (text == null)
        {
            return base.ConvertFrom(context, culture, value);
        }
        string text2 = text.Trim();
        if (text2.Length == 0)
        {
            return null;
        }
        if (culture == null)
        {
            culture = CultureInfo.CurrentCulture;
        }
        char c = culture.TextInfo.ListSeparator[0];
        string[] array = text2.Split(new char[]
        {
            c
        });
        int[] array2 = new int[array.Length];
        TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
        for (int i = 0; i < array2.Length; i++)
        {
            array2[i] = (int)converter.ConvertFromString(context, culture, array[i]);
        }
        if (array2.Length == 3)
        {
            return new Koord(array2[0], array2[1], array2[2]);
        }
        throw new ArgumentException("TextParseFailedFormat");
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == null)
        {
            throw new ArgumentNullException("destinationType");
        }
        if (value is Koord)
        {
            if (destinationType == typeof(string))
            {
                Koord Koord = (Koord)value;
                if (culture == null)
                {
                    culture = CultureInfo.CurrentCulture;
                }
                string separator = culture.TextInfo.ListSeparator + " ";
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
                string[] array = new string[3];
                int num = 0;
                array[num++] = converter.ConvertToString(context, culture, Koord.X);
                array[num++] = converter.ConvertToString(context, culture, Koord.Y);
                array[num++] = converter.ConvertToString(context, culture, Koord.Z);
                return string.Join(separator, array);
            }
            if (destinationType == typeof(InstanceDescriptor))
            {
                Koord Koord2 = (Koord)value;
                ConstructorInfo constructor = typeof(Koord).GetConstructor(new Type[]
                {
                    typeof(double),
                    typeof(double),
                    typeof(double)
                });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[]
                    {
                        Koord2.X,
                        Koord2.Y,
                        Koord2.Z
                    });
                }
            }
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
    {
        if (propertyValues == null)
        {
            throw new ArgumentNullException("propertyValues");
        }
        object obj = propertyValues["X"];
        object obj2 = propertyValues["Y"];
        object obj3 = propertyValues["Z"];
        if (obj == null || obj2 == null || obj3 == null || !(obj is double) || !(obj2 is double) || !(obj3 is double))
        {
            throw new ArgumentException("PropertyValueInvalidEntry");
        }
        return new Koord((double)obj, (double)obj2, (double)obj3);
    }

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

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Koord), attributes);
        return properties.Sort(new string[]
        {
            "X",
            "Y",
            "Z"
        });
    }

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

基本上在所有这些设置完成之后,修改任何对象列表(测试块或每个测试块中的像素)都没有问题
希望如果有人跨过这个线程,这会对他们有所帮助。

最好的问候

Robin Blood

PS:在 PropertyGrid 中编辑没有问题,也许你只是没有正确理解你的构造函数!?
https://i.sstatic.net/LD3zf.png

I know this Topic is more than 2 years old, but maybe this could be interesting for you.

I had a similar Problem.
Starting with: I need a Point in 3D-Space which should be configurable in Property-Grid
For this I created a Class Koord. To make it changeable in PropertyGrid, I created a new Class "KoordConverter : TypeConverter"
This is used in a Vexel (check Wikipedia to find out what it's for :-) )

To create an TestBock (some 3D-Object) I'm using a List of Vexels.
Unfortunately I need a List of TestBlocks in my Program, Visible through the Property-Grid.

To start Topmost:

public partial class FormMain : Form
{
    private BlockProperties _bp = new BlockProperties();

    public FormMain()
    {
        InitializeComponent();
        pgProperties.SelectedObject = _bp;
    }
[...]
}

The Class BlockProperties includes the List of TestBocks which I filled a bit to show you what's inside.

class BlockProperties
{
    public List<TestBocks> Testing { get; set; }

    public BlockProperties()
    {
        Testing = new List<TestBocks>(3);

        List<Vexel> t1 = new List<Vexel>(1);
        t1.Add(new Vexel(new Koord(1,0,1), 1));

        List<Vexel> t2 = new List<Vexel>(2);
        t2.Add(new Vexel(new Koord(2, 0, 1), 2));
        t2.Add(new Vexel(new Koord(2, 0, 2), 2));

        List<Vexel> t3 = new List<Vexel>(3);
        t3.Add(new Vexel(new Koord(3, 0, 1), 3));
        t3.Add(new Vexel(new Koord(3, 0, 2), 3));
        t3.Add(new Vexel(new Koord(3, 0, 3), 3));

        TestBocks tb1 = new TestBocks();
        tb1.Koords = t1;

        TestBocks tb2 = new TestBocks();
        tb2.Koords = t2;

        TestBocks tb3 = new TestBocks();
        tb3.Koords = t3;

        Testing.Add(tb1);
        Testing.Add(tb2);
        Testing.Add(tb3);
    [...]
    }
[...]
}

Next is my TestBlock class, which is simply straight forward

[Serializable]
public class TestBocks
{
    public List<Vexel> Vexels{ get; set; }
    public TestBocks()
    {
        Vexels = new List<Vexel>();
    }
}

In the Vexels is most of the magic I need for my Program:
I even put a ToString() here to make it easy during debugging.

public class Vexel
{
    private Koord _origin;
    private double _extent;

    public Koord Origin { get { return _origin; }  set { _origin = value; } }

    public double Extent { get { return _extent; } set { _extent = value; } }

    public string ToString()
    {
        NumberFormatInfo nFormatInfo = new NumberFormatInfo
        {
            NumberDecimalSeparator = ".",
            NumberGroupSeparator = ""
        }; 
        return String.Format(nFormatInfo, "Origin;{0};{1};{2};Extent;{3}", _origin.X, _origin.Y, _origin.Z, _extent);
    }

    public Vexel()
    {
        _origin = new Koord(0,0,0);
        Extent = 0;
    }

    public Vexel(Koord origin, double extent)
    {
        //TODO do some checking
        _origin = origin;
        _extent = extent;
    }

So far everything worked fine for the PropertyGrid, but I could not edit the Koords.
The Class was pretty simple but not editable in the PropertyGrid.
Adding a TypeConverterClass solved this Problem (you can find the TypeConverter below the code of the Koord)

[TypeConverter(typeof(KoordConverter))]
[Serializable]
public class Koord
{
    private double p_1;
    private double p_2;
    private double p_3;

    public Koord(double x, double y, double z)
    {
        this.p_1 = x;
        this.p_2 = y;
        this.p_3 = z;
    }

    public string ToString()
    {
        return String.Format("X;{0};Y;{1};Z;{2}", p_1, p_2, p_3);
    }

    public double X { get { return p_1; } }
    public double Y { get { return p_2; } }
    public double Z { get { return p_3; } }
}

The Typeconverter was the most complicated code to write. You can find it below:

public class KoordConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        string text = value as string;
        if (text == null)
        {
            return base.ConvertFrom(context, culture, value);
        }
        string text2 = text.Trim();
        if (text2.Length == 0)
        {
            return null;
        }
        if (culture == null)
        {
            culture = CultureInfo.CurrentCulture;
        }
        char c = culture.TextInfo.ListSeparator[0];
        string[] array = text2.Split(new char[]
        {
            c
        });
        int[] array2 = new int[array.Length];
        TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
        for (int i = 0; i < array2.Length; i++)
        {
            array2[i] = (int)converter.ConvertFromString(context, culture, array[i]);
        }
        if (array2.Length == 3)
        {
            return new Koord(array2[0], array2[1], array2[2]);
        }
        throw new ArgumentException("TextParseFailedFormat");
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == null)
        {
            throw new ArgumentNullException("destinationType");
        }
        if (value is Koord)
        {
            if (destinationType == typeof(string))
            {
                Koord Koord = (Koord)value;
                if (culture == null)
                {
                    culture = CultureInfo.CurrentCulture;
                }
                string separator = culture.TextInfo.ListSeparator + " ";
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
                string[] array = new string[3];
                int num = 0;
                array[num++] = converter.ConvertToString(context, culture, Koord.X);
                array[num++] = converter.ConvertToString(context, culture, Koord.Y);
                array[num++] = converter.ConvertToString(context, culture, Koord.Z);
                return string.Join(separator, array);
            }
            if (destinationType == typeof(InstanceDescriptor))
            {
                Koord Koord2 = (Koord)value;
                ConstructorInfo constructor = typeof(Koord).GetConstructor(new Type[]
                {
                    typeof(double),
                    typeof(double),
                    typeof(double)
                });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[]
                    {
                        Koord2.X,
                        Koord2.Y,
                        Koord2.Z
                    });
                }
            }
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
    {
        if (propertyValues == null)
        {
            throw new ArgumentNullException("propertyValues");
        }
        object obj = propertyValues["X"];
        object obj2 = propertyValues["Y"];
        object obj3 = propertyValues["Z"];
        if (obj == null || obj2 == null || obj3 == null || !(obj is double) || !(obj2 is double) || !(obj3 is double))
        {
            throw new ArgumentException("PropertyValueInvalidEntry");
        }
        return new Koord((double)obj, (double)obj2, (double)obj3);
    }

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

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Koord), attributes);
        return properties.Sort(new string[]
        {
            "X",
            "Y",
            "Z"
        });
    }

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

Basically after all of this was set up, It was no ploblem to modify any List of objects (TestBlocks or the Vexels within each TestBlock)
Hope it helps someone if they step over this Thread.

Best Regards

Robin Blood

PS:Editing is no problem in the PropertyGrid, maybe you just didn't get your constructors right !?
https://i.sstatic.net/LD3zf.png

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文