views:

210

answers:

2

I have a custom control which has a property of type Collection< System.Drawing.Point >. When I use CollectionEditor to edit this property, the CollectionEditor window shows "Object does not match target type." for the "X" and "Y" properties. But if I use System.Drawing.PointF instead, there's no failure.

Could anyone tell me why?

+1  A: 

I'm no .NET / C# expert, but the issue appears to be somewhere within the PointConverter class, which is used as the TypeConverterAttribute for the System.Drawing.Point class. The Collection Editor must be using something within the PointConverter class that fails.

I suspect PointConverter because the PointF class has no TypeConverterAttribute, and it works fine.

In the following example, which I cobbled together using some code from MSDN, your problem is seen when using the Point class in a collection, but not with the MyPoint class which is using a custom TypeConverter.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Globalization;

namespace WindowsControlLibrary1
{
    public class MyTypeConverter : TypeConverter
    {
        // Overrides the CanConvertFrom method of TypeConverter.
        // The ITypeDescriptorContext interface provides the context for the
        // conversion. Typically, this interface is used at design time to 
        // provide information about the design-time container.
        public override bool CanConvertFrom(ITypeDescriptorContext context,
           Type sourceType)
        {

            if (sourceType == typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom(context, sourceType);
        }
        // Overrides the ConvertFrom method of TypeConverter.
        public override object ConvertFrom(ITypeDescriptorContext context,
           CultureInfo culture, object value)
        {
            if (value is string)
            {
                string[] v = ((string)value).Split(new char[] { ',' });
                return new MyPoint(int.Parse(v[0]), int.Parse(v[1]));
            }
            return base.ConvertFrom(context, culture, value);
        }
        // Overrides the ConvertTo method of TypeConverter.
        public override object ConvertTo(ITypeDescriptorContext context,
           CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return ((MyPoint)value).X + "," + ((MyPoint)value).Y;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    [SerializableAttribute]
    [TypeConverterAttribute(typeof(MyTypeConverter))]
    public struct MyPoint
    {
        private int x;
        private int y;

        public MyPoint(int _x, int _y)
        {
            x = _x;
            y = _y;
        }

        public int X
        {
            get { return x; }
            set { x = value; }
        }
        public int Y
        {
            get { return y; }
            set { y = value; }
        }

    }

    public partial class UserControl1 : UserControl
    {
        private List<System.Drawing.Point> points;
        private List<System.Drawing.PointF> pointfs;
        private List<MyPoint> mypoints;


        public List<System.Drawing.Point> PointList
        {
            get{ return points;}
            set{ points = value;}
        }

        public List<System.Drawing.PointF> PointFList
        {
            get {return pointfs;}
            set{pointfs = value;}
        }

        public List<MyPoint> MyPointList
        {
            get { return mypoints; }
            set { mypoints = value; }
        }

        public UserControl1()
        {
            InitializeComponent();
        }
    }
}
bde
Thanks bde. I find that if I make the TypeConverter.GetCreateInstanceSupported() return true. It will not function well
smwikipedia
GetCreateInstance() returning true actually means that your type is immutable (or at least one of your properties is read-only), that is, a new instance needs to be created if you want to modify a property. Unfortunately this means that it cannot always be avoided.
kicsit
+1  A: 

The difference between Point and PointF lies indeed with PointConverter. Why this causes a problem is quite a long story, but at the end of the day it boils down to the following:

The System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor) implementation in System.ComponentModel.Design.CollectionEditor .CollectionEditorCollectionForm.SelectionWrapper simply returns this.

According to the MSDN page of the aforementioned method of the ICustomTypeDescriptor interface, an implementation should

Return(s) an object that contains the property described by the specified property descriptor.

If I understand it correctly, in this case the implementation contradicts the documentation.

This is based on some research of my own, so don't take it for granted. I posted a report of this issue on Microsoft Connect, so hopefully we'll know for sure in a few days. I'll report back when an answer is received.

kicsit