HOW TO:實作型別轉換子
型別轉換子可用來轉換資料型別之間的值,並可在設計階段提供文字到值的轉換或提供可供選取的值的下拉式清單來協助設定屬性。 如果適當設定,型別轉換子可以使用 InstanceDescriptor 和 System.Reflection 物件產生屬性組態程式碼,提供設計工具序列化系統產生可在執行階段初始化屬性的程式碼時所需的資訊。
值轉譯的型別轉換子
型別轉換子在設計階段和執行階段可用於字串至數值的轉換或轉譯支援的資料型別。 在主應用程式中,例如表單設計工具中的屬性瀏覽器,型別轉換子允許屬性值對使用者以文字形式表示,並且它們可以將使用者輸入的文字轉換成適當資料型別。
大部原生資料 (Native Data) 型別 (Int32、String、列舉型別等) 具有預設型別轉換子,以提供字串至數值的轉換,並執行驗證檢查。 預設的型別轉換子在 System.ComponentModel 命名空間中,且命名為 TypeConverterNameConverter。 您可以在預設功能不足以應付您的需要時,擴充型別轉換子,或在定義無相關聯的型別轉換子的自訂型別時,實作自訂型別轉換子。
注意事項 |
---|
TypeConverterAttribute 屬性通常套用至屬性或資料成員,以便與型別轉換子產生關聯。如果 TypeConverterAttribute 套用至型別,它就不需要重新套用至該型別的屬性或資料成員。 |
型別轉換子的實作不受任何使用者介面功能影響。 因此相同型別轉換子都可以在 Windows Form 和 Web Form 兩處套用。
若要實作可將字串轉譯成點的簡單型別轉換子
定義從 TypeConverter 衍生的類別。
覆寫會指定轉換子可從哪個型別轉換的 CanConvertFrom 方法。 這個方法是多載的。
覆寫會實作轉換的 ConvertFrom 方法。 這個方法是多載的。
覆寫會指定轉換子可轉換為哪個型別的 CanConvertTo 方法。 覆寫這個方法以轉換為字串型別是沒必要的。 這個方法是多載的。
覆寫會實作轉換的 ConvertTo 方法。 這個方法是多載的。
覆寫會執行驗證的 IsValid(ITypeDescriptorContext, Object) 方法。 這個方法是多載的。
以下的程式碼範例實作可將 String 型別轉換為 Point 型別而將 Point 轉換為 String 的型別轉換子。 在這個範例中並未覆寫 CanConvertTo 和 IsValid(ITypeDescriptorContext, Object) 方法。
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);
}
}
為屬性視窗提供標準值清單的型別轉換子
型別轉換子可為屬性視窗控制項中的型別提供值清單。 型別轉換子提供型別的標準值集合時,屬性視窗控制項中相關型別屬性的值輸入欄位會顯示向下鍵,只要按一下此鍵就會顯示用來設定屬性值的值清單。
在設計階段環境屬性瀏覽器中選取與這個型別轉換子有關聯的型別屬性時,值輸入欄位將包含能顯示可選取屬性型別標準值下拉式清單的按鈕。
若要實作能在屬性瀏覽器中提供標準值下拉式清單的簡單型別轉換子
定義從 TypeConverter 衍生的類別。
覆寫 GetStandardValuesSupported 方法,並傳回 true。
覆寫 GetStandardValues 方法,並傳回包含屬性型別標準值的 TypeConverter.StandardValuesCollection。 屬性標準值必須與屬性本身的型別相同。
覆寫 CanConvertFrom 方法,並為字串型別的 sourceType 參數值傳回 true。
覆寫 ConvertFrom 方法,並根據 value 參數為屬性傳回適當值。
套用 TypeConverterAttribute,指出您正在提供標準值集合之型別的型別轉換子型別。
下列範例示範的型別轉換子,為有關聯的型別屬性提供屬性視窗控制項的標準值清單。 型別轉換子範例支援有關聯的整數型別的屬性。 若要在 Visual Studio 中使用範例,請將程式碼編譯至類別庫 (Class Library),並將 IntStandardValuesControl 元件加入至 [工具箱]。 接著將 IntStandardValuesControl 執行個體 (Instance) 加入設計模式中的表單,並在選取控制項時捲動至 [屬性] 視窗中的 TestInt 屬性。 選取屬性的值輸入欄位時會顯示向下鍵,只要按一下此鍵就會顯示標準值下拉式清單。 輸入整數值,此值就會加入至標準值清單,並將屬性設定成指定值。
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
在執行階段產生屬性初始設定程式碼的型別轉換子
.NET Framework 提供可以在設計階段產生將於執行階段初始化屬性的動態屬性初始設定程式碼的能力。
開發人員可以建置能產生建構函式架構初始設定程式碼的型別轉換子。 這些型別轉換子可以使用在設計階段設定的值來動態產生建構函式程式碼,以便在執行階段設定型別屬性。 型別轉換子會實作邏輯來設定屬性建構函式的型別和值。
如果除了建構函式之外還必須產生程式碼來初始化屬性,您可以實作自訂 CodeDomSerializer 並套用能讓型別的 CodeDomSerializer 與型別產生關聯的 DesignerSerializerAttribute,以動態產生程式碼。 通常是注重動態產生元件初始設定的控制或自訂程式碼時,才使用這個方法。 如需這個方法的詳細資訊,請參閱 CodeDomSerializer 的文件。
若要建置自訂建構函式架構屬性初始設定式,您必須讓型別轉換子與要初始化的屬性型別產生關聯,而且型別轉換子必須能轉換成 InstanceDescriptor。
若要實作能產生建構函式架構屬性初始設定程式碼的型別轉換子
定義從 TypeConverter 衍生的類別。
覆寫 CanConvertTo 方法。 如果 destinationType 參數等於 InstanceDescriptor 型別,則會傳回 true。
覆寫 ConvertTo 方法。 如果 destinationType 參數等於 InstanceDescriptor 型別,則會建構並傳回代表要產生程式碼的建構函式和建構函式引數的 InstanceDescriptor。 若要建立代表適當建構函式和參數的 InstanceDescriptor,請使用您正在探查的建構函式的適當方法簽章來呼叫 GetConstructor 或 GetConstructors 方法,再從您正在初始化的屬性 Type 取得 ConstructorInfo。 接著,建立新執行個體描述項,並傳送代表要使用的建構函式型別的型別 ConstructorInfo 和符合建構函式簽章的參數物件陣列。
下列範例實作能為 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);
}
編譯程式碼
- 當您開發自訂 TypeConverter 時,建議將組建編號設為依每個組建遞增。 這會防止在設計環境中建立快取的舊版本 TypeConverter。