Implementing Type Conversion

It is important for a visual framework to support type conversion. For example, controls have graphical properties, but it is often difficult or impossible to show an image in the small space provided in the Properties window. For the Properties window the path to the image might be fine, but the GUI needs to display the actual image. This duality constitutes a type conversion of an image between a file path and the actual image. Other kinds of data need other kinds of conversion; for instance, a color may be rendered as text when serialized to a resource file, but the actual color is rendered in the GUI. Because various kinds of data conversions are needed to support the IDE and runtime applications, a general conversion mechanism is needed. .NET supplies two general conversion mechanisms.

If you define a new type, you can implement the IConvertible interface, which supports one-way, runtime conversion between a new type and an existing type. The mechanism for conversion ”using the IConvertible interface ”includes the shared methods in the System.Convert class. The process implements IConvertible , calls System.Convert , and uses members that make up the IConvertible interface to perform the conversion. For instance, System.Convert.ToBoolean tests an object to see if it implements IConvertible and then invokes the IConvertible.ToBoolean method. You aren't required to perform the conversion; simply provide the ToBoolean method. If it doesn't make sense to convert your object to a Boolean, raise an exception.

If you want to implement design time and runtime type conversion, you will want to implement a TypeConverter subclass. TypeConverter objects exist to support design time conversion, such as converting the file path of an image between the path and the image, depending on the context.

To demonstrate IConvertible and TypeConverter , I defined a new class, Circle , which supports what may be reasonable conversions for both runtime and design time type conversion. For instance, if we elect to use Circle as a property in a component, we may prefer to show the center point and radius values rather than try to render the circle in the Properties window. The subsections that follow contain the implementations of Circle , the conversion code, and some test code. (You can run and test the example code by downloading ConversionDemo.sln .)

Implementing the IConvertible Interface

Like all interfaces, IConvertible has specific members that we must implement. These methods are GetTypeCode , ToBoolean , ToByte , ToChar , ToDateTime , ToDecimal , ToDouble , ToInt16 , ToInt32 , ToByte , ToString , ToType , ToUInt16 , ToUInt32 , and TUInt64 . You might recognize these as members of the System.Convert class.

In general, implement IConvertible under the following conditions:

  • When you need to perform conversions to general, system types using System.Convert

  • When you need to perform the conversion only at runtime

  • When you need to convert only from a new type to an existing type but not back again

Listing 9.13 contains a reasonable implementation of the Circle structure. Because we need a class in which to hold the interface members, the Circle structure itself implements the IConvertible interface.

Listing 9.13 Implementing the Circle Structure and the IConvertible Interface
 1:  Imports System.ComponentModel 2: 3:  <TypeConverter(GetType(CircleConverter))> _ 4:  Public Structure Circle 5:    Implements IConvertible 6: 7:    Private FCenter As Point 8:    Private FRadius As Single 9: 10:   Public Sub New(ByVal X As Integer, _ 11:     ByVal Y As Integer, ByVal Radius As Single) 12:     FCenter = New Point(X, Y) 13:     FRadius = Radius 14:   End Sub 15: 16:   Public Sub New(ByVal Center As Point, _ 17:     ByVal Radius As Single) 18:     FCenter = Center 19:     FRadius = Radius 20:   End Sub 21: 22:   Public Property Center() As Point 23:   Get 24:     Return FCenter 25:   End Get 26:   Set(ByVal Value As Point) 27:     FCenter = Value 28:   End Set 29:   End Property 30: 31:   Public ReadOnly Property Left() As Integer 32:   Get 33:     Return FCenter.X - FRadius \ 2 34:   End Get 35:   End Property 36: 37:   Public ReadOnly Property Top() As Integer 38:   Get 39:     Return FCenter.Y - FRadius \ 2 40:   End Get 41:   End Property 42: 43:   Public ReadOnly Property Radius() As Single 44:   Get 45:     Return FRadius 46:   End Get 47:   End Property 48: 49:   Public ReadOnly Property Height() As Integer 50:   Get 51:     Return Convert.ToInt32(FRadius) 52:   End Get 53:   End Property 54: 55:   Public ReadOnly Property Width() As Integer 56:   Get 57:     Return Convert.ToInt32(FRadius) 58:   End Get 59:   End Property 60: 61:   Public ReadOnly Property ToBoundingRectangle() _ 62:     As Rectangle 63:   Get 64:     Return New Rectangle(Left, Top, Width, Height) 65:   End Get 66:   End Property 67: 68:   Public ReadOnly Property ToBoundingRectangleF() _ 69:     As RectangleF 70:   Get 71:     Return New RectangleF(Left, Top, Width, Height) 72:   End Get 73:   End Property 74: 75:   Public ReadOnly Property Area() As Single 76:   Get 77:     Return Math.PI * Math.Pow(FRadius, 2) 78:   End Get 79:   End Property 80: 81:   Public ReadOnly Property Circumference() As Single 82:   Get 83:     Return 2 * Math.PI * FRadius 84:   End Get 85:   End Property 86: 87:   Public ReadOnly Property Diameter() As Single 88:   Get 89:     Return 2 * FRadius 90:   End Get 91:   End Property 92: 93:   Private Function GetTypeCode() As TypeCode _ 94:     Implements IConvertible.GetTypeCode 95:     Return TypeCode.Object 96:   End Function 97: 98:   Private Function ToBoolean( _ 99:     ByVal provider As IFormatProvider) As Boolean _ 100:    Implements IConvertible.ToBoolean 101: 102:    ThrowException("conversion to Boolean not supported") 103:    Return False 104:  End Function 105: 106:  Private Function ToByte( _ 107:    ByVal provider As IFormatProvider) As Byte _ 108:    Implements IConvertible.ToByte 109: 110:    ThrowException("conversion to Byte not supported") 111:    Return 0 112:  End Function 113: 114:  Private Function ToChar( _ 115:    ByVal provider As IFormatProvider) As Char _ 116:    Implements IConvertible.ToChar 117: 118:    ThrowException("conversion to Char not supported") 119:    Return Chr(0) 120:  End Function 121: 122:  Private Function ToDateTime( _ 123:    ByVal provider As IFormatProvider) As DateTime _ 124:    Implements IConvertible.ToDateTime 125: 126:    ThrowException("conversion to DateTime not supported") 127:    Return DateTime.Now 128:  End Function 129: 130:  Private Function ToDecimal( _ 131:    ByVal provider As IFormatProvider) As Decimal _ 132:    Implements IConvertible.ToDecimal 133: 134:    ThrowException("conversion to Decimal not supported") 135:    Return Decimal.Zero 136:  End Function 137: 138:  Private Function ToDouble( _ 139:    ByVal provider As IFormatProvider) As Double _ 140:    Implements IConvertible.ToDouble 141: 142:    ThrowException("conversion to Double not supported") 143:    Return Double.MinValue 144:  End Function 145: 146:  Private Function ToInt16( _ 147:    ByVal provider As IFormatProvider) As Int16 _ 148:    Implements IConvertible.ToInt16 149: 150:    ThrowException("conversion to Int16 not supported") 151:    Return Int16.MinValue 152:  End Function 153: 154:  Private Function ToInt32( _ 155:    ByVal provider As IFormatProvider) As Int32 _ 156:    Implements IConvertible.ToInt32 157: 158:    ThrowException("conversion to Int32 not supported") 159:    Return Int32.MinValue 160:  End Function 161: 162:  Private Function ToInt64( _ 163:    ByVal provider As IFormatProvider) As Int64 _ 164:    Implements IConvertible.ToInt64 165: 166:    ThrowException("conversion to Int64 not supported") 167:    Return Int64.MinValue 168:  End Function 169: 170:  Private Function ToSingle( _ 171:    ByVal provider As IFormatProvider) As Single _ 172:    Implements IConvertible.ToSingle 173: 174:    ThrowException("conversion to Single not supported") 175:    Return Single.MinValue 176: 177:  End Function 178: 179:  Private Function ToUInt16( _ 180:    ByVal provider As IFormatProvider) As UInt16 _ 181:    Implements IConvertible.ToUInt16 182: 183:    ThrowException("conversion to UInt16 not supported") 184:    Return UInt16.Parse("0") 185:  End Function 186: 187:  Private Function ToUInt32( _ 188:    ByVal provider As IFormatProvider) As UInt32 _ 189:    Implements IConvertible.ToUInt32 190: 191:    ThrowException("conversion to UInt32 not supported") 192:    Return UInt32.Parse("0") 193:  End Function 194: 195:  Private Function ToUInt64( _ 196:    ByVal provider As IFormatProvider) As UInt64 _ 197:    Implements IConvertible.ToUInt64 198: 199:    ThrowException("conversion to UInt64 not supported") 200:    Return UInt64.Parse("0") 201:  End Function 202: 203:  Private Function ToSByte( _ 204:    ByVal provider As IFormatProvider) As SByte _ 205:    Implements IConvertible.ToSByte 206: 207:    ThrowException("conversion to SByte not supported") 208:    Return SByte.Parse("0") 209:  End Function 210: 211:  Private Overloads Function ToString( _ 212:    ByVal provider As IFormatProvider) As String _ 213:    Implements IConvertible.ToString 214: 215:    Return String.Format("{0},{1},{2}", _ 216:      FCenter.X, FCenter.Y, FRadius.ToString()) 217: 218:  End Function 219: 220:  Public Function ToType( _ 221:    ByVal conversionType As Type, _ 222:    ByVal provider As IFormatProvider) As Object _ 223:    Implements IConvertible.ToType 224: 225:    If (conversionType Is GetType(String)) Then 226:      Return Me.GetType 227:    Else 228:      ThrowException(String.Format( _ 229:        "conversion to {0} not 229: supported", _ 230:        conversionType.ToString)) 231:    End If 232: 233:  End Function 234: 235: 236:  Private Sub ThrowException(ByVal message As String) 237:    Throw New InvalidCastException(message) 238:  End Sub 239: 240: End Structure 

The listing is quite long for a book but is included in its entirety for completeness. A circle is defined by a center point and radius. I included methods to calculate the area and diameter and included the Implements IConvertible statement (line 5) to indicate that Circle implements, or realizes, the IConvertible interface.

All the methods in Listing 9.13 are self-explanatory. It is important to note that only conversions that made sense were actually implemented to perform a conversion. Conversions that don't make sense ”like ToDateTime ”simply throw an exception. For the Circle structure it only made sense to implement GetTypeCode , ToType , and ToString . You will find practical implementations for these three methods; every other IConvertible method throws an exception. It is up to the consumer to trap exceptions when attempting a type conversion.

GetTypeCode (lines 93 through 96) returns the enumerated TypeCode value that defines the common type system type. ToType (lines 220 through 233) returns the Type object for supported conversion types. The Circle structure can be converted to a string representation, so the Type object for String is returned (lines 225 and 226) or an exception is thrown (lines 228 to 230) based on the conversionType argument. Finally, ToString (lines 211 through 218) actually performs the conversion to suitable, comma-delimited string representation of a circle.

Implementing a Type Converter

TypeConverter is a class that supports both design time and runtime type conversion. This class is especially useful with classes that need to be represented at design time in places like the Properties window. For our example, assuming a control had a circle property, it would be impractical to render the circle in the small field in the Properties window. However, the center point and radius numbers could easily be displayed. To support this practical conversion behavior, Listing 9.14 demonstrates a type converter for our Circle structure.

Listing 9.14 Implementing a Custom Type Converter for the Circle Structure
 1:  Imports System.ComponentModel 2:  Imports System.Text.RegularExpressions 3:  Imports System.Globalization 4: 5:  Public Class CircleConverter 6:    Inherits TypeConverter 7: 8:    Private Const Pattern As String = _ 9:      "^\d+,\d+,((\d+)(\d+.\d+))$" 10: 11:   Public Overloads Overrides Function CanConvertFrom( _ 12:     ByVal context As ITypeDescriptorContext, _ 13:     ByVal sourceType As Type) As Boolean 14: 15:     Return sourceType Is GetType(Rectangle) Or _ 16:       sourceType Is GetType(RectangleF) Or _ 17:       sourceType Is GetType(String) Or _ 18:       MyBase.CanConvertFrom(context, sourceType) 19: 20:   End Function 21: 22:   Private Function IsValidString( _ 23:     ByVal Value As Object) As Boolean 24: 25:     Return Value.GetType Is GetType(String) _ 26:       AndAlso Regex.IsMatch(CType(Value, String), _ 27:         Pattern) 28: 29:   End Function 30: 31:   Public Overloads Overrides Function ConvertFrom( _ 32:     ByVal context As ITypeDescriptorContext, _ 33:     ByVal info As CultureInfo, _ 34:     ByVal Value As Object) As Object 35: 36:     If (CanConvertFrom(Value.GetType)) Then 37: 38:       If (IsValidString(Value)) Then 39: 40:         Dim s() As String = _ 41:           CType(Value, String).Split(New Char() {","}) 42: 43:         Return New Circle(Convert.ToInt32(s(0)), _ 44:           Convert.ToInt32(s(1)), Convert.ToSingle(s(1))) 45: 46:       ElseIf (Value.GetType Is GetType(Rectangle)) Then 47: 48:         Dim R As Rectangle = CType(Value, Rectangle) 49:         Return New Circle(R.X + R.Width \ 2, _ 50:           R.Y + R.Height \ 2, R.Width \ 2 + R.Height \ 2) 51: 52:       ElseIf (Value.GetType Is GetType(RectangleF)) Then 53: 54:         Dim R As RectangleF = CType(Value, RectangleF) 55:         Return New Circle(R.X + R.Width \ 2, _ 56:           R.Y + R.Height \ 2, R.Width \ 2 + R.Height \ 2) 57:       Else 58:         Return MyBase.ConvertFrom(context, info, Value) 59:       End If 60: 61:     End If 62: 63:     Return MyBase.ConvertFrom(context, info, Value) 64:   End Function 65: 66: 67:   Public Overloads Overrides Function CanConvertTo( _ 68:     ByVal context As ITypeDescriptorContext, _ 69:     ByVal destinationType As Type) As Boolean 70: 71:     Return destinationType Is GetType(Rectangle) Or _ 72:       destinationType Is GetType(RectangleF) Or _ 73:       destinationType Is GetType(String) Or _ 74:       MyBase.CanConvertTo(context, destinationType) 75: 76:   End Function 77: 78:   Public Overridable Overloads Function ConvertTo( _ 79:     ByVal context As ITypeDescriptorContext, _ 80:     ByVal culture As CultureInfo, _ 81:     ByVal value As Object, _ 82:     ByVal destinationType As Type _ 83:     ) As Object 84: 85:     If (CanConvertTo(destinationType)) Then 86:       If (destinationType Is GetType(Rectangle)) Then 87:         Return CType(value, Circle).ToBoundingRectangle 88:       ElseIf (destinationType Is GetType(RectangleF)) Then 89:         Return CType(value, Circle).ToBoundingRectangleF 90:       ElseIf (destinationType Is GetType(String)) Then 91:         Return CType(value, Circle).ToString() 92:       End If 93:     Else 94:       Return MyBase.ConvertTo(context, culture, _ 95:         value, destinationType) 96:     End If 97: 98:   End Function 99: 100: End Class 

To implement the TypeConverter class we need to inherit from System.ComponentModel.TypeConverter and override the behavior of four inherited methods: CanConvertFrom , ConvertFrom , CanConvertTo , and ConvertTo . The names of these methods imply the forward and backward nature of a type converter. CanConvertFrom answers the question, "Which types can I convert to my type?" ConvertFrom performs the conversion from some other type to my type. CanConvertTo answers the question, "Which types can my type convert to?" ConvertTo actually performs the conversion to the request type.

As you might imagine, this involves a significant amount of type checking. We must examine the type to convert to or from and answer the question of suitability. For example, lines 11 through 20 in Listing 9.14 indicate that CircleConverter can create a Circle (that is, convert from any of the test types to a Circle ) from a Rectangle , RectangleF , String , or any type the base class can convert from. The Rectangle integer can be used as a bounding rectangle, and the approximate dimensions of a circle can be derived from a bounding rectangle. The RectangleF structure is a rectangle with floating-point corners and can be used to approximate a circle in the same way that a Rectangle integer can be used. Finally, a String type that contains three numbers representing the center and radius could be used to derive a circle. The ITypeDescriptorContext interface can be used to determine the context (think "containing thing") in which the conversion is being requested . You can include a condition in which a conversion is not supported for a particular context.

The ConvertFrom method (lines 31 through 64) is probably the most challenging method to implement. We have to write code that will convert from any particular type that we support to values sufficient to create an instance of our type. Because we support rectangles and strings, we need to write code that converts a rectangle or string to arguments suitable for a circle. For example, lines 36 through 44 determine whether the Value argument is an instance of a type we want to convert from. Line 38 checks to see whether Value is a string in the correct format. We defined the format, so we know it and can test for it in advance, using a regular expression to test the format and the String.Split method to actually subdivide the string. There are two points of interest here. First, we could have performed both the pattern check and the split with a regular expression. Second, we might want to add some error code rather than assuming there are three strings in the array and that those strings can be converted to the indicated type (lines 43 and 44). The two ElseIf conditions convert Rectangle types to Circle types, and the final Else condition invokes the base class behavior.

CanConvertTo and ConvertTo perform the analogous inverse conversion operations and are a bit simpler in our case. For example, converting from a Circle type to a Rectangle type is relatively easy because this behavior is supported in the Circle structure itself.

NOTE

Before you create a new converter, check the .NET Framework to determine whether a converter already exists. Check the TypeConverter Hierarchy help topic for a comprehensive list of converters. There are about three dozen listed in the Visual Studio .NET help documentation.

Associating a Type Converter with a Convertible Type

Next we need to tell the Circle structure and everybody else about the CircleConverter class. As you might have guessed, we use attributes to form the association between TypeConverter and Circle .

Use the TypeConverterAttribute to associate a custom type converter with the class that supports type conversion. Pass the Type object or the fully qualified name of the custom type converter to the TypeConverterAttribute . Line 3 of Listing 9.13 shows the TypeConverterAttribute applied with the Type object (returned by GetType ) of the custom type converter, CircleConverter .

Using the IConvertible Behavior

You can download the ConversionDemo.sln program to test the implementation of IConvertible and CircleConverter . To invoke IConvertible methods, call System.Convert , passing an instance of a Circle object to the Convert class's shared methods. Listing 9.15 shows three event handlers that indirectly invoke methods in the Circle structure and attempt type conversions using the IConvertible interface.

Listing 9.15 Performing Runtime Type Conversion
 Private Sub Button1_Click(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles Button1.Click   TextBox1.Text = Convert.ToString(Circle) End Sub Private Sub Button2_Click(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles Button2.Click   TextBox2.Text = Convert.GetTypeCode(Circle).ToString() End Sub Private Sub Button3_Click(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles Button3.Click   TextBox3.Text = Convert.ToDecimal(Circle) End Sub 

Each conversion is a single line of code that invokes a shared member of the System.Convert class. Double-checking with Rotor we can verify (assuming you can read C# code) that the shared conversion methods attempt to convert the target object to an IConvertible instance and invoke the implementation of the like method on the object itself. For example, our Circle object will be typecast to an IConvertible instance, and Convert.ToString will invoke the equivalent of CType(Circle, IConvertible).ToBoolean(Nothing) , where Nothing is a null IFormatProvider . The shared Convert methods are overloaded. If you pass an IFormatProvider to ToBoolean , the provider will be passed on to the interface method instead of the literal Nothing . (The .NET Framework is implemented in C#; thus null is actually passed and the methods are declared static . Null and static are equivalent to VB's Nothing and Shared , respectively.)

IFormatProviders are objects that provide formatting instructions for conversions. Existing IFormatProviders include CultureInfo , DateTimeFormatInfo , and NumberFormatInfo . You can create a custom IFormatProvider for your types too. For example, we could implement CircleFormatInfo to describe relevant string representations of a circle. (Try this as an exercise.)

Using the Type Conversion Behavior

Type conversion can occur at design time or runtime. At design time it may be invoked by the IDE when an object needs to be displayed in the Properties window, for example, and we can perform explicit type conversion at runtime. Listing 9.16 demonstrates how to use the TypeDescriptor class to request the type converter for an object; subsequently, that type converter is used to perform the testing and conversion.

Listing 9.16 Performing Type Conversion Programmatically with a Type Descriptor
 1:  Imports System.ComponentModel 2: 3:  Public Class Form1 4:      Inherits System.Windows.Forms.Form 5: 6:  [ Windows Form Designer generated code ] 7: 8:    Private Sub Button1_Click(ByVal sender As System.Object, _ 9:      ByVal e As System.EventArgs) Handles Button1.Click 10:     TextBox1.Text = Convert.ToString(Circle) 11:   End Sub 12: 13:   Private Circle As Circle 14: 15:   Private Sub Form1_Paint(ByVal sender As Object, _ 16:     ByVal e As System.Windows.Forms.PaintEventArgs) _ 17:     Handles MyBase.Paint 18: 19:     e.Graphics.DrawEllipse(Pens.Red, _ 20:       Circle.ToBoundingRectangle) 21:   End Sub 22: 23:   Private Sub Button2_Click(ByVal sender As System.Object, _ 24:     ByVal e As System.EventArgs) Handles Button2.Click 25:     TextBox2.Text = Convert.GetTypeCode(Circle).ToString() 26:   End Sub 27: 28:   Private Sub Button3_Click(ByVal sender As System.Object, _ 29:     ByVal e As System.EventArgs) Handles Button3.Click 30:     TextBox3.Text = Convert.ToDecimal(Circle) 31:   End Sub 32: 33:   Private Sub Form1_Load(ByVal sender As System.Object, _ 34:     ByVal e As System.EventArgs) Handles MyBase.Load 35: 36:     Circle = New Circle(New Point(Me.Width \ 2, _ 37:       Me.Height \ 2), Height \ 3) 38:   End Sub 39: 40:   Private Sub MenuItem4_Click(ByVal sender As System.Object, _ 41:     ByVal e As System.EventArgs) Handles MenuItem4.Click 42: 43:     Dim About As String = _ 44:       "IConvertible and TypeConverter Demo" & vbCrLf & _ 45:       "Copyright " & Chr(169) & " 2002. All Rights Reserved." & _ 46:       vbCrLf & _ 47:       "By Paul Kimmel. pkimmel@softconcepts.com" 48: 49:     MessageBox.Show(About, "About", MessageBoxButtons.OK, _ 50:        MessageBoxIcon.Information) 51:   End Sub 52: 53:   Private Sub MenuItem2_Click(ByVal sender As System.Object, _ 54:     ByVal e As System.EventArgs) Handles MenuItem2.Click 55: 56:     Close() 57: 58:   End Sub 59: 60:   Private Sub MenuItem6_Click(ByVal sender As System.Object, _ 61:     ByVal e As System.EventArgs) Handles MenuItem6.Click 62: 63:     Dim R = New Rectangle(100, 200, 75, 75) 64:     If (TypeDescriptor.GetConverter(GetType(Circle)). _ 65:       CanConvertFrom(GetType(Rectangle))) Then 66: 67:       Circle = TypeDescriptor.GetConverter(GetType(Circle)). _ 68:         ConvertFrom(R) 69:     End If 70:     Invalidate() 71:   End Sub 72: 73:   Private Sub MenuItem8_Click(ByVal sender As System.Object, _ 74:     ByVal e As System.EventArgs) Handles MenuItem8.Click 75: 76:     Dim R = New RectangleF(150.5, 190.8, 33.7, 75.1) 77:     If (TypeDescriptor.GetConverter(GetType(Circle)). _ 78:       CanConvertFrom(GetType(RectangleF))) Then 79: 80:       Circle = TypeDescriptor.GetConverter(GetType(Circle)). _ 81:         ConvertFrom(R) 82:     End If 83:     Invalidate() 84:   End Sub 85: 86:   Private Sub MenuItem7_Click(ByVal sender As System.Object, _ 87:     ByVal e As System.EventArgs) Handles MenuItem7.Click 88: 89:     Dim C As String = "200,200,160" 90:     If (TypeDescriptor.GetConverter(GetType(Circle)). _ 91:       CanConvertFrom(GetType(String))) Then 92: 93:       Circle = TypeDescriptor.GetConverter(GetType(Circle)). _ 94:         ConvertFrom(C) 95:     End If 96:     Invalidate() 97: 98:   End Sub 99: End Class 

Listing 9.16 contains the code for the main form in ConversionDemo.sln . (You can see the repeated code from Listing 9.15, too.) Three menu items are similar in nature in lines 60 through 98. The code declares some type ”for example, a string in line 89 ”that is an alternate representation of a circle. Following the representative type we use the TypeDescriptor.GetConverter shared method and Reflection implicitly to get the type converter for a type (lines 93 and 94) and invoke one of the test operations. In lines 90 and 91 we get the type converter for the Circle structure and ask whether a circle can be created from a given string. If the test succeeds, the related conversion method is invoked, again using the type converter. Lines 93 and 94 get the CircleConverter and convert the string C to an instance of the private field Circle .

Finally, the Invalidate method causes the form to be repainted, and the paint event handler (lines 15 through 21) draws the circle on the test form.

TIP

If you use the Option Strict On directive, you will need to perform explicit type casts using CType to convert the generic return type of ConvertFrom and ConvertTo to the converted type. (No explicit type casting is shown in Listings 9.15 and 9.16.)

Use almost identical code to determine whether a circle can be converted to an alternate type, invoking the CanConvertTo and ConvertTo methods and retrieving the converted type from the ConvertTo method.



Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net