Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CollectionEditor yielding "Object does not match target type." for System.Drawing.Point

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.

Can anyone please explain why this difference occurs?

like image 910
smwikipedia Avatar asked Apr 08 '10 05:04

smwikipedia


2 Answers

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.

like image 67
kicsit Avatar answered Nov 05 '22 05:11

kicsit


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();
        }
    }
}
like image 2
WildCrustacean Avatar answered Nov 05 '22 06:11

WildCrustacean