Compartir a través de


Implementar un conversor de tipos

Se puede utilizar un convertidor de tipos para convertir valores entre tipos de datos, y ayudar en la configuración de propiedades en tiempo de diseño al proporcionar una conversión de texto a valor o una lista desplegable de valores que se pueden seleccionar. Si se configura correctamente, un convertidor de tipos puede producir un código de configuración de propiedades utilizando el objeto InstanceDescriptor y System.Reflection para proporcionar al sistema de serialización del diseñador la información necesaria para producir código que inicialice la propiedad en tiempo de ejecución.

Convertidores de tipos para la traducción de valores

Los convertidores de tipos se utilizan principalmente para conversiones o traducciones de cadena en valor y para tipos de datos compatibles en tiempo de diseño y en tiempo de ejecución. En un host, tal como un examinador de propiedades de un diseñador de formularios, los convertidores de tipos permiten representar un valor de propiedad como texto para el usuario, y pueden convertir el texto escrito por el usuario en un valor del tipo de datos apropiado.

La mayoría de los tipos de datos nativos (Int32, String, tipos de enumeración, etc.) tienen conversores de tipos predeterminados que permiten realizar conversiones de cadena en valor y comprobaciones de validación. Los convertidores de tipos predeterminados se encuentran en el espacio de nombres System.ComponentModel y se denominan NombreDeConvertidorDeTiposConverter. Cuando la funcionalidad predeterminada no se ajuste a sus necesidades, puede extender un conversor de tipos, o puede implementar un conversor de tipos personalizado si define un tipo personalizado que no tiene asociado ningún conversor de tipos.

**Nota   **Generalmente, el atributo TypeConverterAttribute se aplica a una propiedad o a un miembro de datos para asociarlos a un conversor de tipos. Si TypeConverterAttribute se aplica a un tipo, no es necesario volver a aplicarlo a las propiedades o a los miembros de datos de ese tipo.

La implementación de un conversor de tipos no guarda relación con la funcionalidad de la interfaz de usuario. De ahí que el mismo conversor de tipos se pueda aplicar tanto en formularios Windows Forms como en formularios Web Forms.

Para implementar un convertidor de tipos sencillo que pueda convertir una cadena a un punto

  1. Defina una clase que se derive de System.ComponentModel.TypeConverter.
  2. Reemplace el método CanConvertFrom que especifica desde qué tipo puede realizar la conversión el conversor. Este método está sobrecargado.
  3. Reemplace el método ConvertFrom que implementa la conversión. Este método está sobrecargado.
  4. Reemplace el método CanConvertTo que especifica en qué tipo puede realizar la conversión el conversor. No es necesario reemplazar este método si el destino de la conversión es un tipo de cadena. Este método está sobrecargado.
  5. Reemplace el método ConvertTo que implementa la conversión. Este método está sobrecargado.
  6. Reemplace el método IsValid que realiza la validación. Este método está sobrecargado.

En el ejemplo siguiente, se implementa un convertidor de tipos que convierte un tipo String en un tipo System.Drawing.Point y System.Drawing.Point en String. En el ejemplo, no se reemplazan los métodos CanConvertTo e IsValid.

Option Explicit 
Option Strict

Imports System
Imports System.ComponentModel
Imports System.Globalization
Imports System.Drawing

Public Class PointConverter
   Inherits 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 Overrides Overloads Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
      If sourceType Is GetType(String) Then
         Return True
      End If
      Return MyBase.CanConvertFrom(context, sourceType)
   End Function
   
   ' Overrides the ConvertFrom method of TypeConverter.
   Public Overrides Overloads Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
      If TypeOf value Is String Then
         Dim v As String() = CStr(value).Split(New Char() {","c})
         Return New Point(Integer.Parse(v(0)), Integer.Parse(v(1)))
      End If
      Return MyBase.ConvertFrom(context, culture, value)
   End Function
   
   ' Overrides the ConvertTo method of TypeConverter.
   Public Overrides Overloads Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
      If destinationType Is GetType(String) Then
         Return CType(value, Point).X & "," & CType(value, Point).Y
      End If
      Return MyBase.ConvertTo(context, culture, value, destinationType)
   End Function
End Class
[C#]
using System;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;

public class PointConverter : 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 Point(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 ((Point)value).X + "," + ((Point)value).Y;
      }
      return base.ConvertTo(context, culture, value, destinationType);
   }
}

Convertidores de tipos que proporcionan una lista de valores estándar a una cuadrícula de propiedades

Un convertidor de tipos puede proporcionar una lista de valores para un tipo de datos en un control de cuadrícula de propiedades. Cuando un convertidor de tipos proporciona un conjunto de valores estándar para un determinado tipo de datos, cualquier campo de entrada para una propiedad del tipo de datos asociado al convertidor, en un control de cuadrícula de propiedades, mostrará una flecha abajo; al hacer clic en ella se muestra una lista de valores con los que establecer el valor de la propiedad.

Cuando se selecciona una propiedad del tipo con el que está asociado este convertidor de tipos, en un examinador de propiedades del entorno en tiempo de diseño, el campo de entrada del valor contendrá un botón que muestra una lista desplegable de los valores estándar para el tipo de propiedad de la que se puede seleccionar un valor.

Para implementar un convertidor de tipos sencillo que proporciona una lista desplegable de valores estándar en un examinador de propiedades

  1. Defina una clase que se derive de System.ComponentModel.TypeConverter.
  2. Reemplace el método GetStandardValuesSupported y devuelva el valor true.
  3. Reemplace el método GetStandardValues y devuelva StandardValuesCollection que contiene los valores estándar para el tipo de datos de la propiedad. Los valores estándar de un tipo de datos de la propiedad deben ser del tipo cadena de caracteres.
  4. Reemplace el método CanConvertFrom y devuelva el valor true para un valor de parámetro sourceType de tipo cadena de caracteres.
  5. Reemplace el método ConvertFrom y devuelva el valor apropiado para la propiedad basado en el parámetro value.
  6. Aplique un atributo TypeConverterAttribute que indique el tipo de su convertidor de tipos al tipo que se está proporcionando como conjunto de valores estándar.

El siguiente ejemplo muestra un convertidor de tipos que proporciona una lista de valores estándar a un control de cuadrícula de propiedades para una propiedad del tipo al que se asocia. El convertidor de tipos de ejemplo es compatible con propiedades de tipo entero a las que se ha asociado. Para utilizar un ejemplo de Visual Studio .NET, compile el código en una biblioteca de clases, y después agregue el componente IntStandardValuesControl al Cuadro de herramientas. Agregue una instancia del componente IntStandardValuesControl a un formulario en modo de diseño, y desplácese a la propiedad TestInt de la ventana de Propiedades mientras está seleccionado el control. Al seleccionar el campo de entrada de valor de la propiedad se muestra una flecha abajo que muestra una lista desplegable de valores estándar cuando se hace clic sobre ella. Al introducir un valor entero se agregará el valor a la lista de valores estándar y se establece la propiedad en el valor especificado.

using System;
using System.ComponentModel;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;

namespace StandardValuesTest
{  
    public class StandardValuesIntConverter : System.ComponentModel.TypeConverter
    {
        private ArrayList values;
        public StandardValuesIntConverter()
        {
            // Initializes the standard values list with defaults.
            values = new ArrayList(new int[] { 1, 2, 3, 4, 5 });
        }

        // Indicates this converter provides a list of standard values.
        public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;
        }

        // Returns a StandardValuesCollection of standard value objects.
        public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
        {        
            // Passes the local integer array.
            StandardValuesCollection svc = 
                new StandardValuesCollection(values);       
            return svc;
        }

        // Returns true for a sourceType of string to indicate that 
        // conversions from string to integer are supported. (The 
        // GetStandardValues method requires a string to native type 
        // conversion because the items in the drop-down list are 
        // translated to string.)
        public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
        {
            if( sourceType == typeof(string) )
                return true;
            else 
                return base.CanConvertFrom(context, sourceType);
        }

        // If the type of the value to convert is string, parses the string 
        // and returns the integer to set the value of the property to. 
        // This example first extends the integer array that supplies the 
        // standard values collection if the user-entered value is not 
        // already in the array.
        public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if( value.GetType() == typeof(string) )
            {
                // Parses the string to get the integer to set to the property.
                int newVal = int.Parse((string)value);
            
                // Tests whether new integer is already in the list.
                if( !values.Contains(newVal) )
                {
                    // If the integer is not in list, adds it in order.
                    values.Add(newVal);
                    values.Sort();
                }                                
                // Returns the integer value to assign to the property.
                return newVal;
            }
            else
                return base.ConvertFrom(context, culture, value);
        }
    }

    // Provides a test control with an integer property associated with 
    // the StandardValuesIntConverter type converter.
    public class IntStandardValuesControl : System.Windows.Forms.UserControl
    {
        [TypeConverter(typeof(StandardValuesIntConverter))]
        public int TestInt
        {
            get
            {
                return this.integer_field;
            }
            set
            {
                if(value.GetType() == typeof(int))
                    this.integer_field = value;
            }
        }
        private int integer_field = 0;
      
        public IntStandardValuesControl()
        {
            this.BackColor = Color.White;
            this.Size = new Size(472, 80);
        }

        // OnPaint override displays instructions for the example.
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            if(this.DesignMode)
            {
                e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Blue), 5, 5);
                e.Graphics.DrawString("The type converter for the TestInt property of this", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 20);
                e.Graphics.DrawString("component provides a list of standard values to the", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 30);
                e.Graphics.DrawString("Properties window. Setting a value through a property", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 40);
                e.Graphics.DrawString("grid adds it to the list of standard values.", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 50);             
            }
            else
            {
                e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Blue), 5, 5);         
                e.Graphics.DrawString("This control was intended for use in design mode.", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 20);       
            }
        }
    }
} 
[Visual Basic]
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Collections
Imports System.Drawing
Imports System.Windows.Forms

Namespace StandardValuesTest

    Public Class StandardValuesIntConverter
        Inherits System.ComponentModel.TypeConverter

        Private values As ArrayList

        Public Sub New()
            ' Initializes the standard values list with defaults.
            values = New ArrayList(New Integer() {1, 2, 3, 4, 5})
        End Sub 'New

        ' Indicates this type converter provides a list of standard values.
        Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function 'GetStandardValuesSupported

        ' Returns a StandardValuesCollection of standard value objects.
        Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
            ' Passes the local integer array.
            Dim svc As New StandardValuesCollection(values)
            Return svc
        End Function 'GetStandardValues

        ' Returns true for a sourceType of string to indicate that 
        ' conversions from string to integer are supported. (The 
        ' GetStandardValues method requires a string to native type 
        ' conversion because the items in the drop-down list are 
        ' translated to string.)
        Public Overloads Overrides Function CanConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal sourceType As System.Type) As Boolean
            If sourceType Is GetType(String) Then
                Return True
            Else
                Return MyBase.CanConvertFrom(context, sourceType)
            End If
        End Function 'CanConvertFrom

        ' If the type of the value to convert is string, parses the string 
        ' and returns the integer to set the value of the property to. 
        ' This example first extends the integer array that supplies the 
        ' standard values collection if the user-entered value is not 
        ' already in the array.
        Public Overloads Overrides Function ConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object) As Object
            If value.GetType() Is GetType(String) Then
                ' Parses the string to get the integer to set to the property.
                Dim newVal As Integer = Integer.Parse(CStr(value))

                ' Tests whether new integer is already in the list.
                If Not values.Contains(newVal) Then
                    ' If the integer is not in list, adds it in order.
                    values.Add(newVal)
                    values.Sort()
                End If
                ' Returns the integer value to assign to the property.
                Return newVal
            Else
                Return MyBase.ConvertFrom(context, culture, value)
            End If
        End Function 'ConvertFrom
    End Class 'StandardValuesIntConverter

    ' Provides a test control with an integer property associated with the 
    ' StandardValuesIntConverter type converter.
    Public Class IntStandardValuesControl
        Inherits System.Windows.Forms.UserControl

        <TypeConverter(GetType(StandardValuesIntConverter))> _
        Public Property TestInt() As Integer
            Get
                Return Me.integer_field
            End Get
            Set(ByVal Value As Integer)
                If Value.GetType() Is GetType(Integer) Then
                    Me.integer_field = Value
                End If
            End Set
        End Property
        Private integer_field As Integer = 0

        Public Sub New()
            Me.BackColor = Color.White
            Me.Size = New Size(472, 80)
        End Sub 'New

        ' OnPaint override displays instructions for the example.
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            If Me.DesignMode Then
                e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Blue), 5, 5)
                e.Graphics.DrawString("The type converter for the TestInt property of this", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 20)
                e.Graphics.DrawString("component provides a list of standard values to the", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 30)
                e.Graphics.DrawString("Properties window. Setting a value through a property", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 40)
                e.Graphics.DrawString("grid adds it to the list of standard values.", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 50)
            Else
                e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Blue), 5, 5)
                e.Graphics.DrawString("This control was intended for use in design mode.", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 20)
            End If
        End Sub 'OnPaint
    End Class 'IntStandardValuesControl
End Namespace 'StandardValuesTest

Convertidores de tipos que generan código para la inicialización de propiedades en tiempo de ejecución

.NET Framework permite generar dinámicamente un código configurable de inicialización de propiedades en tiempo de diseño, que inicializará una propiedad en tiempo de ejecución.

Los programadores pueden crear un convertidor de tipos que produzca un código de inicialización basado en constructores. Estos convertidores de tipos pueden generar código de constructor dinámicamente, mediante valores establecidos en tiempo de diseño para configurar propiedades de un tipo en tiempo de ejecución. El convertidor de tipos implementa la lógica para configurar el tipo y los valores de un constructor para la propiedad.

Si se necesita producir código además de un constructor para inicializar una propiedad, es posible generar código dinámicamente al implementar un CodeDomSerializer y aplicar un atributo DesignerSerializerAttribute que asocie su CodeDomSerializer para un tipo con el tipo al que pertenece la propiedad. Normalmente, este enfoque sólo se utiliza para escenarios en los que es importante la generación de código personalizado o controlado dinámicamente para la inicialización de componentes. Para obtener más información acerca de este enfoque, vea la documentación de CodeDomSerializer

Para crear una propiedad basada en constructores personalizados, se debe asociar un convertidor de tipos al tipo de la propiedad que se va a inicializar, y el convertidor de tipos debe ser capaz de convertirse a una clase InstanceDescriptor.

Para implementar un convertidor de tipos que produzca un código de inicialización basado en constructores.

  1. Defina una clase que se derive de System.ComponentModel.TypeConverter.
  2. Reemplace el método CanConvertTo Si el parámetro destinationType es igual al tipo InstanceDescriptor, devuelva el valor true.
  3. Reemplace el método ConvertTo Si el parámetro destinationType es igual al tipo InstanceDescriptor, construya y devuelva un tipo InstanceDescriptor que represente al constructor y argumentos de constructor para los que generar código. Para generar una clase InstanceDescriptor que represente el constructor y parámetros apropiados, obtenga una clase ConstructorInfo del Type de la propiedad que se está inicializando al llamar a los métodos GetConstructor o GetConstructors con la firma del método apropiado del constructor que se está buscando. A continuación cree un nuevo descriptor de instancias y pase el componente ConstructorInfo para el tipo que representa el tipo de constructor que se va a utilizar con una matriz de objetos de parámetros que coinciden con la firma del constructor.

El ejemplo siguiente implementa un convertidor de tipos que puede generar código de inicialización de propiedades basado en constructores para propiedades del tipo Point.

public class PointConverter : TypeConverter 
{
   public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
   {
      if (destinationType == typeof(InstanceDescriptor)) 
         return true;
      return base.CanConvertTo(context, destinationType);
   }

public override object ConvertTo(ITypeDescriptorContext context, 
CultureInfo culture, object value, Type destinationType) 
{
      // Insert other ConvertTo operations here.
      //
      if (destinationType == typeof(InstanceDescriptor) && 
value is Point) 
   {
         Point pt = (Point)value;

      ConstructorInfo ctor = typeof(Point).GetConstructor(
new Type[] {typeof(int), typeof(int)});
      if (ctor != null) 
      {
         return new InstanceDescriptor(ctor, new object[] {pt.X, pt.Y});
}
}
   return base.ConvertTo(context, culture, value, destinationType);      
}

Vea también

Conversión de tipos generalizada