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

不羁岁月 提交于 2019-12-03 12:59:39
kicsit

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.

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();
        }
    }
}

My solution is before you use collectioneditor to edit list(of point), use TypeDescriptor.AddAttributes(GetType(Drawing.Point), New TypeConverterAttribute()) to set typeconverter of Point to nothing, and after that use TypeDescriptor.AddAttributes(GetType(Drawing.Point), New TypeConverterAttribute(GetType(PointConverter))) to set typeconverter to default.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!