2010-04-08 10 views
8

Tengo un control personalizado que tiene una propiedad del tipo Collection<System.Drawing.Point>. Cuando uso CollectionEditor para editar esta propiedad, la ventana CollectionEditor muestra "Object does not match target type." para las propiedades "X" y "Y". Pero si utilizo System.Drawing.PointF, no hay falla.CollectionEditor produciendo "El objeto no coincide con el tipo de destino". para System.Drawing.Point

¿Puede alguien explicar por qué ocurre esta diferencia?

Respuesta

3

La diferencia entre Point y PointF reside ciertamente en PointConverter. Por qué esto causa un problema es una historia bastante larga, pero al final del día se reduce a lo siguiente:

La implementación System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor) en System.ComponentModel.Design.CollectionEditor .CollectionEditorCollectionForm.SelectionWrapper simplemente devuelve this.

De acuerdo con la página de MSDN del método de la interfaz de ICustomTypeDescriptor antes mencionado, una implementación debe

Return (s) un objeto que contiene la propiedad descrita por el descriptor de propiedad especificada.

Si lo entiendo correctamente, en este caso la implementación contradice la documentación.

Esto se basa en algunas investigaciones propias, por lo que no lo dé por hecho. Publiqué un informe de este problema en Microsoft Connect, así que espero que podamos estar seguros en unos días. Informaré cuando se reciba una respuesta.

2

No soy experto en .NET/C#, pero el problema parece estar en algún lugar dentro de la clase PointConverter, que se usa como TypeConverterAttribute para la clase System.Drawing.Point. El Editor de colecciones debe estar utilizando algo dentro de la clase PointConverter que falla.

Sospecho PointConverter porque la clase PointF no tiene TypeConverterAttribute, y funciona bien.

En el siguiente ejemplo, que he improvisado usando un código de MSDN, su problema se ve cuando se utiliza la clase Point en una colección, pero no con la clase MyPoint que está utilizando una costumbre 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(); 
     } 
    } 
} 
+0

Gracias bde. Encuentro que si hago que TypeConverter.GetCreateInstanceSupported() devuelva true. No funcionará bien – smwikipedia

+0

GetCreateInstance() devuelve verdadero significa que su tipo es inmutable (o al menos una de sus propiedades es de solo lectura), es decir, una nueva instancia debe crearse si desea modificar una propiedad. Lamentablemente, esto significa que no siempre se puede evitar. – kicsit

0

Mi solución es antes de usar collectioneditor para editar la lista (de punto), use TypeDescriptor.AddAttributes(GetType(Drawing.Point), New TypeConverterAttribute()) para configurar typeconverter of Point a nothing, y después de eso use TypeDescriptor.AddAttributes(GetType(Drawing.Point), New TypeConverterAttribute(GetType(PointConverter))) para establecer typeconverter a default.

Cuestiones relacionadas