Implementazione di un convertitore di tipi

Un convertitore di tipi può essere utilizzato per convertire valori tra tipi di dati e per supportare la configurazione di proprietà in fase di progettazione fornendo conversione da testo a valori o un elenco a discesa di valori tra cui scegliere. Se configurato correttamente, un convertitore di tipi è in grado di produrre codice di configurazione di proprietà utilizzando un oggetto InstanceDescriptor e un oggetto System.Reflection per fornire al sistema di serializzazione della finestra di progettazione le informazioni necessarie per produrre il codice per l'inizializzazione della proprietà in fase di esecuzione.

Convertitori di tipi per la traduzione dei valori

I convertitori di tipi possono essere utilizzati per conversioni da stringa a valore o per la traduzione da e verso tipi di dati supportati in fase di progettazione e di esecuzione. In un host quale un visualizzatore proprietà, in una finestra di progettazione di form, i convertitori di tipi consentono al valore di una proprietà di essere rappresentato come testo all'utente e sono in grado di convertire il testo immesso dall'utente in un valore del tipo appropriato.

La maggior parte dei tipi di dati nativi (Int32, String, tipi di enumerazione e altri) dispongono di convertitori di tipi predefiniti che operano conversioni da stringa a valore ed eseguono controlli di convalida. I convertitori di tipi predefiniti si trovano nello spazio dei nomi System.ComponentModel e sono denominati NomeConvertitoreTipoConverter. È possibile estendere un convertitore di tipi quando le funzionalità predefinite non rispondono alle esigenze specifiche nonché implementare un convertitore di tipi personalizzato quando si definisce un tipo personalizzato cui non è associato alcun convertitore di tipi.

**Nota   **Per associare una proprietà o un membro di dati a un convertitore di tipi viene in genere applicato a tale proprietà o membro di dati l'attributo TypeConverterAttribute. Se l'attributo TypeConverterAttribute viene applicato a un tipo, non sarà necessario applicarlo anche alle proprietà o ai membri di dati di tale tipo.

L'implementazione di un convertitore di tipi è indipendente da qualsiasi funzionalità dell'interfaccia utente. Di conseguenza è possibile applicare lo stesso convertitore di tipi sia in Windows Form che in Web Form.

Per implementare un semplice convertitore di tipi in grado di tradurre una stringa in un valore di tipo Point

  1. Definire una classe derivata da System.ComponentModel.TypeConverter.
  2. Sottoporre a override il metodo CanConvertFrom che specifica il tipo convertibile dal convertitore. Si tratta di un metodo di overload.
  3. Sottoporre a override il metodo ConvertFrom che implementa la conversione. Si tratta di un metodo di overload.
  4. Sottoporre a override il metodo CanConvertTo che specifica il tipo in cui il convertitore è in grado di operare la conversione. Non è necessario sottoporre a override questo metodo per operare una conversione a un tipo stringa. Si tratta di un metodo di overload.
  5. Sottoporre a override il metodo ConvertTo che implementa la conversione. Si tratta di un metodo di overload.
  6. Sottoporre a override il metodo IsValid che esegue la convalida. Si tratta di un metodo di overload.

Nell'esempio di codice che segue viene implementato un convertitore di tipi che converte un tipo String in un tipo System.Drawing.Point e viceversa. In questo esempio i metodi CanConvertTo e IsValid non sono sottoposti a override.

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

Convertitori di tipi che forniscono un elenco di valori standard a una griglia delle proprietà

Un convertitore di tipi è in grado di fornire un elenco di valori per un tipo nel controllo di una griglia delle proprietà. Quando un convertitore di tipi fornisce un insieme di valori standard per un tipo, nel campo per l'immissione del valore per una proprietà del tipo associato in un controllo di una griglia delle proprietà viene visualizzata una freccia verso il basso. Quando si fa clic sulla freccia, viene visualizzato un elenco di valori utilizzabili per l'impostazione della proprietà.

Quando una proprietà del tipo a cui è associato questo convertitore di tipi è selezionata in un visualizzatore proprietà di un ambiente di progettazione, il campo per l'immissione di valori conterrà un pulsante tramite cui viene visualizzato un elenco a discesa dei valori standard tra cui è possibile scegliere per il tipo di proprietà.

Per implementare un semplice convertitore di tipi che fornisce un elenco a discesa di valori standard in un visualizzatore proprietà

  1. Definire una classe che deriva da System.ComponentModel.TypeConverter.
  2. Sottoporre a override il metodo GetStandardValuesSupported e restituire un valore true.
  3. Sottoporre a override il metodo GetStandardValues e restituire una raccolta StandardValuesCollection contenente i valori standard per il tipo di proprietà. I valori standard per un tipo di proprietà deve essere di tipo string.
  4. Sottoporre a override il metodo CanConvertFrom e restituire true per un valore di parametro sourceType di tipo string.
  5. Sottoporre a override il metodo ConvertFrom e restituire il valore appropriato per la proprietà in base al parametro value.
  6. Applicare un attributo TypeConverterAttribute che indica il tipo di convertitore di tipi al tipo a cui si sta fornendo un insieme di valori standard.

Nell'esempio riportato di seguito viene illustrato un convertitore di tipi che fornisce un elenco di valori standard al controllo di una griglia delle proprietà, per una proprietà del tipo a cui è associato. Il convertitore di tipi utilizzato nell'esempio supporta proprietà di tipo integer con le quali è stato associato. Per utilizzare l'esempio in Visual Studio .NET compilare il codice in una libreria di classi, quindi aggiungere il componente IntStandardValuesControl alla Casella degli strumenti. Aggiungere un'istanza del controllo IntStandardValuesControl a un form in modalità progettazione e scorrere fino alla proprietà TestInt nella finestra Proprietà mentre il controllo è selezionato. Quando viene selezionato il campo per l'immissione di valori per la proprietà, viene visualizzata una freccia verso il basso. Quando si fa clic sulla freccia, viene visualizzato un elenco a discesa di valori standard. L'immissione di un valore integer abilita l'aggiunta del valore all'elenco di valori standard e l'impostazione della proprietà sul valore specificato.

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

Convertitori di tipi che generano codice per l'inizializzazione di proprietà in fase di esecuzione

In .NET Framework sono fornite le funzioni per generare in fase di esecuzione codice di inizializzazione di proprietà configurabile dinamicamente, il quale inizializzerà una proprietà in fase di esecuzione.

Gli sviluppatori saranno in grado di generare un convertitore di tipi che produca un codice di inizializzazione basato sul costruttore. Tali convertitori di tipi sono in grado di generare il codice del costruttore in modo dinamico utilizzando i valori impostati in fase di progettazione per la configurazione delle proprietà di un tipo in fase di esecuzione. Il convertitore di tipi implementa la logica per configurare il tipo e i valori di un costruttore per la proprietà.

Se si desidera produrre codice diverso da un costruttore per inizializzare una proprietà, è possibile generare il codice in modo dinamico implementando un serializzatore CodeDomSerializer personalizzato e applicando un attributo DesignerSerializerAttribute che associ il serializzatore CodeDomSerializer per un tipo al tipo desiderato. Questo approccio viene generalmente adottato solo in situazioni in cui è importante che la generazione del codice per l'inizializzazione dei componenti sia personalizzata o controllata in modo dinamico. Per ulteriori informazioni su questo approccio, vedere la documentazione per il serializzatore CodeDomSerializer.

Per generare un inizializzatore di proprietà basato sul costruttore è necessario associare un convertitore di tipi al tipo della proprietà da inizializzare e il convertitore di tipi deve essere in grado di convertire un oggetto InstanceDescriptor.

Per implementare un convertitore di tipi che produca codice di inizializzazione basato sul costruttore

  1. Definire una classe che deriva da System.ComponentModel.TypeConverter.
  2. Sottoporre a override il metodo CanConvertTo. Se il parametro destinationType è uguale al tipo InstanceDescriptor, restituire true.
  3. Sottoporre a override il metodo ConvertTo. Se il parametro destinationType è uguale al tipo InstanceDescriptor, costruire e restituire un oggetto InstanceDescriptor che rappresenti il costruttore e i relativi argomenti per cui generare il codice. Per creare un oggetto InstanceDescriptor che rappresenti il costruttore appropriato con i relativi parametri, ottenere un oggetto ConstructorInfo dal tipo Type della proprietà che si sta inizializzando chiamando il metodo GetConstructor oppure GetConstructors con la firma del metodo appropriata del costruttore desiderato. Creare quindi un nuovo descrittore di istanza e passare l'oggetto ConstructorInfo per il tipo che rappresenta il tipo di costruttore da utilizzare, insieme a una matrice di oggetti parametro che corrispondono alla firma del costruttore.

Nell'esempio seguente viene implementato un convertitore di tipi in grado di generare codice di inizializzazione di proprietà basato sul costruttore per proprietà di 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);      
}

Vedere anche

Conversione di tipi generalizzata