Flylib.com

Books Software

 
 
 

4.6 Create an Object That Can Appear in the Component Tray


4.6 Create an Object That Can Appear in the Component Tray

Problem

You want to create a class that has basic design-time support and can be added to a form's component at design-time.

Solution

Derive your class from System.ComponentModel.Component .

Discussion

The .NET class library includes many classes that can be added to a form, Web page, or another type of component at design time. For example, as shown in Figure 4-1, you can add the System.Windows.Forms.Timer object class directly to the component tray of a form, even though it has no visual representation. This allows the programmer to configure properties and connect event handlers at design time.

click to expand
Figure 4-1: A component object in the component tray.

To create a class that supports design-time creation, you must implement the IComponent interface. You can do this directly, or indirectly by deriving from System.ComponentModel.Component or System.ComponentModel.MarshalByValueComponent . The former is used for classes that may be remoted (accessed from another application domain through a proxy), whereas the latter is for objects that may be copied into new application domains. Typically, classes that provide a service derive from Component , while classes that primarily contain data (such as the DataSet ) derive from MarshalByValueComponent .

Once you derive from the component class, you need to add a small amount of boilerplate code to support the disposable pattern because the IComponent interface extends the IDisposable interface. For more information about the IDisposable interface, see recipe 4.5.

Here's a bare-bones example of a component class:

Public Class MyComponent Inherits System.ComponentModel.Component Protected Overloads Overrides Sub Dispose(disposing As Boolean) If disposing Then ' Disposal was triggered manually by the client. ' Call Dispose() on any contained classes. End If ' Release unmanaged resources. ' Set large member

variables

to Nothing (null). ' Call Dispose on the base class. MyBase.Dispose(disposing) End Sub End Class

You should create component classes in a dedicated class library assembly. Once you have compiled the assembly, you can add the component classes to the Toolbox. Simply right-click the Toolbox, choose Add/Remove Items, and select the appropriate assembly. All component classes in the assembly will appear in the Toolbox and can now be dragged and dropped into the component tray (at which point a reference will be added to the assembly in your project). Figure 4-2 shows an example that includes two new components from an assembly.


Figure 4-2: Component objects in the Toolbox.

Note 

The System.ComponentModel namespace includes many attributes you can use to decorate the properties of a component class and influence how they will appear in the Properties window. For example, you can use DescriptionAttribute to add a text description that will appear in the window, DefaultValueAttribute to specify the initial value, DefaultPropertyAttribute to configure which property will be initially selected when the control receives focus at design-time, and so on.



4.7 Create a Convertible Object

Problem

You want to create a class that can be converted to common data types such as Int32 and String .

Solution

Implement the IConvertible interface. Add conversion code for the supported data types, and throw an InvalidCastException for all unsupported data types.

Discussion

The IConvertible interface defines 17 methods for converting an object into basic .NET types. The first method, GetTypeCode , simply returns a value from the System.TypeCode enumeration identifying the type, which will always be TypeCode.Object for your custom classes, as shown here:

Public Function GetTypeCode() As TypeCode _ Implements IConvertible.GetTypeCode Return TypeCode.Object End Function

The other 16 methods perform the actual conversions and begin with the word To , as in ToBoolean , ToByte , ToString , and so on. If a method doesn't apply to your object, simply throw an InvalidCastException in the method.

Here's a partial example with a complex number class:

Public Class ComplexNumber Implements IConvertible Private _Real As Double Private _Imaginary As Double Public Property Real() As Double Get Return _Real End Get Set(ByVal Value As Double) _Real = Value End Set End Property Public Property Imaginary() As Double Get Return _Imaginary End Get Set(ByVal Value As Double) _Imaginary = Value End Set End Property Public Function GetModulus() As Double Return Math.Sqrt(Me.Real ^ 2 + Me.Imaginary ^ 2) End Function Public Function ToBoolean(ByVal provider As System.IFormatProvider) _ As Boolean Implements System.IConvertible.ToBoolean Throw New InvalidCastException End Function Public Function ToDateTime(ByVal provider As System.IFormatProvider) _ As Date Implements System.IConvertible.ToDateTime Throw New InvalidCastException End Function Public Function ToDecimal(ByVal provider As System.IFormatProvider) _ As Decimal Implements System.IConvertible.ToDecimal Return CType(GetModulus(), Decimal) End Function Public Function ToDouble(ByVal provider As System.IFormatProvider) _ As Double Implements System.IConvertible.ToDouble Return GetModulus() End Function ' (Other conversion methods omitted.) End Class

To perform a conversion, a client can call a conversion method directly or use the System.Convert class, which works with any IConvertible object.

Dim MyDouble As Double = Convert.ToDouble(MyComplexNumber)

In addition, IConvertible allows your object to work with some batch conversions. For example, you can use the ArrayList.ToArray method to create a strongly typed array if your ArrayList contains the same type of object, and this type of object implements IConvertible . Recipe 3.7 demonstrates this technique.