Implementing a Custom Component

Creating custom components in Visual Basic 6 was too complicated. The single greatest deterrent to building great components in VB6 was that VB6 did not support inheritance. As a result you could not inherit from a VB6 TextBox control and extend it to do something new. Fortunately, Visual Basic .NET does support true inheritance, and this is all you need to create great components.

The distinction generally made between a component and a control ”even though the terms are often used interchangeably ”is that controls have a visual aspect at runtime and components do not. Examples of components include the Timer , FileSystemWatcher , and EventLog components. Examples of controls include the TextBox , Label , and Button controls. The visual aspect of a control is governed by a Windows handle. The Windows handle is used to send messages like WM_PAINT to a control. In this section I am referring specifically to a custom class that is a nonvisual component.

There are two general approaches you can take when building custom controls. The first approach is to inherit from the System.ComponentModel.Component class and build your component from scratch. The second approach is to find a close existing component and inherit from that close match, extending it to incorporate the new behavior. For our first custom component we will begin with the second, easier, approach.


On a project recently, a newer Windows programmer discovered the EventLog component. Rather than reinvent the wheel, the programmer began using EventLog for Debug and Trace messages. (The EventLog component can be registered as a TraceListener , which means it will receive Trace and Debug messages.) The problem was that every Debug and Trace message was going to the Application log by default, resulting in the Application log repeatedly filling up and throwing up ”a euphemism for an exception.

Using EventLog for this purpose is intended. However, if you try it, send Debug and Trace messages to a custom log and be circumspect about the information you send to the Application log.

A good strategy for logging debug events while you are building and unit testing your application is to use a custom event log. The existing EventLog component supports doing this with some additional configuration steps. Suppose you want to ensure that everyone is using the same log file. You could generalize the existing EventLog class and add this custom class to your project, ensuring that everyone is sending debug information to a custom log rather than filling up the Application log. Listing 9.1 defines a custom EventLog component that inherits from EventLog and ensures that this instance writes to a custom log.

Listing 9.1 Implementing a Custom EventLog Component
 1:  Imports System.Reflection 2: 3:  Public Class DebugEventLog 4:    Inherits System.Diagnostics.EventLog 5: 6:    Private Const LogName As String = "Debug" 7: 8:    Public Sub New() 9:      MyBase.New() 10:     Log = LogName 11:     CheckSource() 12:   End Sub 13: 14:   Private ReadOnly Property SourceName() As String 15:   Get 16:     Return [Assembly].GetExecutingAssembly().FullName 17:   End Get 18:   End Property 19: 20:   Private Sub CheckSource() 21: 22:     ' Source does not exist anywhere 23:     If (Not SourceExists(SourceName)) Then 24:       CreateEventSource(SourceName, LogName) 25:       Source = SourceName 26:     Else 27:       ' Source exists in the right log 28:       If (LogNameFromSourceName(SourceName, _ 29:         MachineName) = LogName) Then 30:         Source = SourceName 31:       Else 32:         MessageBox.Show(Message, "Event Log", _ 33:           MessageBoxButtons.OK, MessageBoxIcon.Information) 34:       End If 35:     End If 36: 37:   End Sub 38: 39:   Private ReadOnly Property Message() As String 40:   Get 41:     Dim Mask As String = _ 42:       "Source {0} already exists in log {1}." + _ 43:       Environment.NewLine + _ 44:       "Provide an alternate source name." 45: 46:     Return String.Format(Mask, SourceName, _ 47:       LogNameFromSourceName(SourceName, MachineName)) 48:   End Get 49:   End Property 50: 51: End Class 

The basic behavior of an Event Log is that log names must be unique on a machine and an event source must be unique across all logs. Hence you may have only one event source with a particular name irregardless of the log that source is associated with. If you are creating EventLog components programmatically and assigning source names, you will need code to ensure the source name is unique. In Listing 9.1, lines 14 through 18 return the assembly name of the assembly containing a particular instance of DebugEventLog . In addition to this name being irregular and unique to an assembly, the CheckSource method in lines 20 through 37 verify that the source name is unique on a particular machine and that our custom Debug log contains that source name.

When you want to ensure that debug code is written to a custom log, you can share a component like DebugEventLog with developers on your team.

The key lesson here is that components do not have to be complex or incorporate large changes to be useful. As a general principle, small, incremental changes are preferable to huge, monolithic changes. The benefit with DebugEventLog is that everyone's code behaves in a consistent way without each programmer needing to implement a copy of the code. Creating components for consistency and convergence is an excellent job for a person designated as a toolsmith .

For now you can test the DebugEventLog control by declaring an instance of it and invoking the WriteEntry method (Listing 9.2). You can find the code for Listings 9.1 and 9.2 in the sample solution file DebugEventLog.sln .

Listing 9.2 Creating and Using the DebugEventLog Control
 1:  Public Class Form1 2:      Inherits System.Windows.Forms.Form 3: 4:  [ Windows Form Designer generated code ] 5: 6:    Private Log As DebugEventLog 7: 8:    Private Sub Form1_Load(ByVal sender As System.Object, _ 9:      ByVal e As System.EventArgs) Handles MyBase.Load 10: 11:     Log = New DebugEventLog() 12: 13:   End Sub 14: 15:   Private Sub Button1_Click(ByVal sender As System.Object, _ 16:     ByVal e As System.EventArgs) Handles Button1.Click 17:     Log.WriteEntry(DateTime.Now.ToString()) 18:   End Sub 19: End Class 

You are not required to register components with the Toolbox or even involve the Toolbox when using components. After all, components are just classes, and you can do everything programmatically. The Toolbox is a convenience mechanism. We will look at how you can place components and controls in the Toolbox in the upcoming section Adding a Control to the Toolbox.

Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel © 2008-2017.
If you may any questions please contact us: