Comment : implémenter un convertisseur de type
Un convertisseur de type peut être utilisé pour convertir des valeurs entre des types de données et pour aider à configurer des propriétés au moment du design en fournissant une conversion de texte en valeur ou une liste déroulante de valeurs dans laquelle une sélection peut être effectuée. S'il est correctement configuré, un convertisseur de type peut produire le code de configuration de la propriété à l'aide de InstanceDescriptor et d'objets System.Reflection pour fournir au système de sérialisation du concepteur les informations nécessaires pour créer le code qui initialise la propriété au moment de l'exécution.
Convertisseurs de type pour la conversion en valeur
Des convertisseurs de type peuvent être utilisés pour des conversions de chaîne en valeur vers ou à partir de types de données pris en charge au moment du design et de l'exécution. Dans un hôte tel que l'Explorateur de propriétés d'un concepteur de formulaires, les convertisseurs de type permettent de représenter une valeur de propriété sous la forme de texte à l'attention de l'utilisateur et ils peuvent convertir le texte entré par l'utilisateur dans une valeur du type de données approprié.
La plupart des types de données natifs (Int32, String, types énumération, etc.) possèdent des convertisseurs de type par défaut qui fournissent des conversions de chaîne en valeur et effectuent des vérifications de validation. Les convertisseurs de type par défaut se trouvent dans l'espace de noms System.ComponentModel et sont nommés NomConvertisseurTypeConverter. Vous pouvez étendre un convertisseur de type si la fonctionnalité par défaut n'est pas adaptée à vos besoins ou implémenter un convertisseur de type personnalisé si vous définissez un type personnalisé auquel aucun convertisseur de type n'est associé.
Notes
Un attribut TypeConverterAttribute est généralement appliqué à une propriété ou à une donnée membre afin de l'associer à un convertisseur de type.Si TypeConverterAttribute est appliqué à un type, il ne doit pas être réappliqué aux propriétés ou aux données membres de ce type.
L'implémentation d'un convertisseur de type est indépendante de toute fonctionnalité de l'interface utilisateur. Par conséquent, le même convertisseur de type peut être appliqué à la fois dans Windows Forms et dans Web Forms.
Pour implémenter un convertisseur de type simple pouvant convertir une chaîne en type Point
Définissez une classe qui dérive de TypeConverter.
Substituez la méthode CanConvertFrom qui spécifie le type à partir duquel le convertisseur peut effectuer la conversion. Cette méthode est surchargée.
Substituez la méthode ConvertFrom qui implémente la conversion. Cette méthode est surchargée.
Substituez la méthode CanConvertTo qui spécifie le type vers lequel le convertisseur peut effectuer la conversion. Il n'est pas nécessaire de substituer cette méthode pour effectuer la conversion en un type string. Cette méthode est surchargée.
Substituez la méthode ConvertTo qui implémente la conversion. Cette méthode est surchargée.
Substituez la méthode IsValid(ITypeDescriptorContext, Object) qui effectue la validation. Cette méthode est surchargée.
L'exemple de code suivant implémente un convertisseur de type qui convertit un type String en Point et un type Point en String. Les méthodes CanConvertTo et IsValid(ITypeDescriptorContext, Object) ne sont pas substituées dans cet exemple.
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
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);
}
}
Convertisseurs de type qui fournissent une liste de valeurs standard à une fenêtre Propriétés
Un convertisseur de type peut fournir une liste de valeurs pour un type dans un contrôle de fenêtre Propriétés. Lorsqu'un convertisseur de type fournit un ensemble de valeurs standard pour un type, le champ d'entrée des valeurs pour une propriété du type associé dans un contrôle de fenêtre Propriétés affiche une flèche bas ; lorsque vous sélectionnez cette flèche, vous obtenez une liste de valeurs à affecter à la propriété.
Lorsqu'une propriété du type auquel ce convertisseur de type est associé est sélectionnée dans un Explorateur de propriétés d'un environnement au moment du design, le champ d'entrée des valeurs contient un bouton qui affiche une liste déroulante des valeurs standard du type de propriété dans laquelle vous pouvez effectuer une sélection.
Pour implémenter un convertisseur de type simple qui fournit une liste déroulante de valeurs standard dans un Explorateur de propriétés
Définissez une classe qui dérive de TypeConverter.
Substituez la méthode GetStandardValuesSupported et retournez true.
Substituez la méthode GetStandardValues et retournez une StandardValuesCollection contenant les valeurs standard pour le type de propriété. Les valeurs standard d'une propriété doivent être du même type que la propriété elle-même.
Substituez la méthode CanConvertFrom et retournez true pour une valeur de paramètre sourceType de type string.
Substituez la méthode ConvertFrom et retournez la valeur appropriée de la propriété sur la base du paramètre value.
Appliquez un TypeConverterAttribute qui indique le type de votre convertisseur de type au type pour lequel vous fournissez un ensemble de valeurs standard.
L'exemple suivant illustre un convertisseur de type qui fournit une liste de valeurs standard à un contrôle de fenêtre Propriétés pour une propriété à laquelle le type est associé. Le convertisseur de type pris en exemple prend en charge des propriétés de type entier avec lesquelles il a été associé. Pour utiliser l'exemple dans Visual Studio, compilez le code dans une bibliothèque de classes et ajoutez le composant IntStandardValuesControl à la Boîte à outils. Ajoutez une instance de IntStandardValuesControl à un formulaire en mode design et faites défiler la fenêtre Propriétés pour atteindre la propriété TestInt pendant que le contrôle est sélectionné. Lorsque vous sélectionnez le champ d'entrée des valeurs de la propriété, une flèche bas apparaît. Lorsque vous cliquez sur cette flèche, une liste déroulante de valeurs standard s'affiche. Si vous entrez une valeur entière, celle-ci est ajoutée à la liste des valeurs standard et la valeur spécifiée est affectée à la propriété.
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);
}
}
}
}
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
Convertisseurs de type qui génèrent du code pour l'initialisation de propriétés au moment de l'exécution
Le .NET Framework offre la possibilité de générer du code d'initialisation de propriété dynamique au moment du design, destiné à initialiser une propriété au moment de l'exécution.
Les développeurs peuvent créer un convertisseur de type qui produit du code d'initialisation basé sur un constructeur. Ces convertisseurs de type peuvent générer du code de constructeur dynamiquement à l'aide de valeurs définies au moment du design afin de configurer les propriétés d'un type au moment de l'exécution. Le convertisseur de type implémente la logique pour configurer le type et les valeurs d'un constructeur pour la propriété.
Si vous devez générer du code en plus d'un constructeur pour initialiser une propriété, il est possible de le faire dynamiquement en implémentant un CodeDomSerializer personnalisé et en appliquant un DesignerSerializerAttribute qui associe votre CodeDomSerializer pour un type au type. Cette approche n'est généralement utilisée que pour les scénarios dans lesquels la génération de code personnalisé ou contrôlé dynamiquement pour l'initialisation d'un composant est importante. Pour plus d'informations sur cette approche, consultez la documentation sur CodeDomSerializer.
Pour générer un initialiseur de propriété basé sur un constructeur personnalisé, vous devez associer un convertisseur de type au type de la propriété à initialiser ; le convertisseur de type doit être en mesure de convertir en InstanceDescriptor.
Pour implémenter un convertisseur de type qui produit du code d'initialisation de propriété basé sur un constructeur
Définissez une classe qui dérive de TypeConverter.
Substituez la méthode CanConvertTo. Si le paramètre destinationType est équivalent au type InstanceDescriptor, retournez true.
Substituez la méthode ConvertTo. Si le paramètre destinationType est équivalent au type InstanceDescriptor, construisez et retournez InstanceDescriptor qui représente le constructeur et les arguments du constructeur pour lequel du code doit être généré. Pour créer un InstanceDescriptor qui représente le constructeur et les paramètres appropriés, procurez-vous un ConstructorInfo du Type de la propriété que vous initialisez en appelant la méthode GetConstructor ou GetConstructors à l'aide de la signature de méthode appropriée du constructeur que vous recherchez. Puis créez un nouveau descripteur d'instance et passez ConstructorInfo pour le type qui représente le type de constructeur à utiliser, avec un tableau des objets Parameter qui correspondent à la signature de constructeur.
L'exemple suivant implémente un convertisseur de type capable de générer du code d'initialisation de propriétés basées sur un constructeur pour des propriétés de type 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);
}
Compilation du code
- Lorsque vous développez votre TypeConverterpersonnalisé, il est recommandé de définir le numéro de génération à incrémenter avec chaque génération. Cela empêche des versions plus anciennes, mises en cache de votre TypeConverter d'être créées dans l'environnement de design.