
- •Using Your Sybex Electronic Book
- •Acknowledgments
- •Contents at a Glance
- •Introduction
- •Who Should Read This Book?
- •How About the Advanced Topics?
- •The Structure of the Book
- •How to Reach the Author
- •The Integrated Development Environment
- •The Start Page
- •Project Types
- •Your First VB Application
- •Making the Application More Robust
- •Making the Application More User-Friendly
- •The IDE Components
- •The IDE Menu
- •The Toolbox Window
- •The Solution Explorer
- •The Properties Window
- •The Output Window
- •The Command Window
- •The Task List Window
- •Environment Options
- •A Few Common Properties
- •A Few Common Events
- •A Few Common Methods
- •Building a Console Application
- •Summary
- •Building a Loan Calculator
- •How the Loan Application Works
- •Designing the User Interface
- •Programming the Loan Application
- •Validating the Data
- •Building a Math Calculator
- •Designing the User Interface
- •Programming the MathCalculator App
- •Adding More Features
- •Exception Handling
- •Taking the LoanCalculator to the Web
- •Working with Multiple Forms
- •Working with Multiple Projects
- •Executable Files
- •Distributing an Application
- •VB.NET at Work: Creating a Windows Installer
- •Finishing the Windows Installer
- •Running the Windows Installer
- •Verifying the Installation
- •Summary
- •Variables
- •Declaring Variables
- •Types of Variables
- •Converting Variable Types
- •User-Defined Data Types
- •Examining Variable Types
- •Why Declare Variables?
- •A Variable’s Scope
- •The Lifetime of a Variable
- •Constants
- •Arrays
- •Declaring Arrays
- •Initializing Arrays
- •Array Limits
- •Multidimensional Arrays
- •Dynamic Arrays
- •Arrays of Arrays
- •Variables as Objects
- •So, What’s an Object?
- •Formatting Numbers
- •Formatting Dates
- •Flow-Control Statements
- •Test Structures
- •Loop Structures
- •Nested Control Structures
- •The Exit Statement
- •Summary
- •Modular Coding
- •Subroutines
- •Functions
- •Arguments
- •Argument-Passing Mechanisms
- •Event-Handler Arguments
- •Passing an Unknown Number of Arguments
- •Named Arguments
- •More Types of Function Return Values
- •Overloading Functions
- •Summary
- •The Appearance of Forms
- •Properties of the Form Control
- •Placing Controls on Forms
- •Setting the TabOrder
- •VB.NET at Work: The Contacts Project
- •Anchoring and Docking
- •Loading and Showing Forms
- •The Startup Form
- •Controlling One Form from within Another
- •Forms vs. Dialog Boxes
- •VB.NET at Work: The MultipleForms Project
- •Designing Menus
- •The Menu Editor
- •Manipulating Menus at Runtime
- •Building Dynamic Forms at Runtime
- •The Form.Controls Collection
- •VB.NET at Work: The DynamicForm Project
- •Creating Event Handlers at Runtime
- •Summary
- •The TextBox Control
- •Basic Properties
- •Text-Manipulation Properties
- •Text-Selection Properties
- •Text-Selection Methods
- •Undoing Edits
- •VB.NET at Work: The TextPad Project
- •Capturing Keystrokes
- •The ListBox, CheckedListBox, and ComboBox Controls
- •Basic Properties
- •The Items Collection
- •VB.NET at Work: The ListDemo Project
- •Searching
- •The ComboBox Control
- •The ScrollBar and TrackBar Controls
- •The ScrollBar Control
- •The TrackBar Control
- •Summary
- •The Common Dialog Controls
- •Using the Common Dialog Controls
- •The Color Dialog Box
- •The Font Dialog Box
- •The Open and Save As Dialog Boxes
- •The Print Dialog Box
- •The RichTextBox Control
- •The RTF Language
- •Methods
- •Advanced Editing Features
- •Cutting and Pasting
- •Searching in a RichTextBox Control
- •Formatting URLs
- •VB.NET at Work: The RTFPad Project
- •Summary
- •What Is a Class?
- •Building the Minimal Class
- •Adding Code to the Minimal Class
- •Property Procedures
- •Customizing Default Members
- •Custom Enumerations
- •Using the SimpleClass in Other Projects
- •Firing Events
- •Shared Properties
- •Parsing a Filename String
- •Reusing the StringTools Class
- •Encapsulation and Abstraction
- •Inheritance
- •Inheriting Existing Classes
- •Polymorphism
- •The Shape Class
- •Object Constructors and Destructors
- •Instance and Shared Methods
- •Who Can Inherit What?
- •Parent Class Keywords
- •Derived Class Keyword
- •Parent Class Member Keywords
- •Derived Class Member Keyword
- •MyBase and MyClass
- •Summary
- •On Designing Windows Controls
- •Enhancing Existing Controls
- •Building the FocusedTextBox Control
- •Building Compound Controls
- •VB.NET at Work: The ColorEdit Control
- •VB.NET at Work: The Label3D Control
- •Raising Events
- •Using the Custom Control in Other Projects
- •VB.NET at Work: The Alarm Control
- •Designing Irregularly Shaped Controls
- •Designing Owner-Drawn Menus
- •Designing Owner-Drawn ListBox Controls
- •Using ActiveX Controls
- •Summary
- •Programming Word
- •Objects That Represent Text
- •The Documents Collection and the Document Object
- •Spell-Checking Documents
- •Programming Excel
- •The Worksheets Collection and the Worksheet Object
- •The Range Object
- •Using Excel as a Math Parser
- •Programming Outlook
- •Retrieving Information
- •Recursive Scanning of the Contacts Folder
- •Summary
- •Advanced Array Topics
- •Sorting Arrays
- •Searching Arrays
- •Other Array Operations
- •Array Limitations
- •The ArrayList Collection
- •Creating an ArrayList
- •Adding and Removing Items
- •The HashTable Collection
- •VB.NET at Work: The WordFrequencies Project
- •The SortedList Class
- •The IEnumerator and IComparer Interfaces
- •Enumerating Collections
- •Custom Sorting
- •Custom Sorting of a SortedList
- •The Serialization Class
- •Serializing Individual Objects
- •Serializing a Collection
- •Deserializing Objects
- •Summary
- •Handling Strings and Characters
- •The Char Class
- •The String Class
- •The StringBuilder Class
- •VB.NET at Work: The StringReversal Project
- •VB.NET at Work: The CountWords Project
- •Handling Dates
- •The DateTime Class
- •The TimeSpan Class
- •VB.NET at Work: Timing Operations
- •Summary
- •Accessing Folders and Files
- •The Directory Class
- •The File Class
- •The DirectoryInfo Class
- •The FileInfo Class
- •The Path Class
- •VB.NET at Work: The CustomExplorer Project
- •Accessing Files
- •The FileStream Object
- •The StreamWriter Object
- •The StreamReader Object
- •Sending Data to a File
- •The BinaryWriter Object
- •The BinaryReader Object
- •VB.NET at Work: The RecordSave Project
- •The FileSystemWatcher Component
- •Properties
- •Events
- •VB.NET at Work: The FileSystemWatcher Project
- •Summary
- •Displaying Images
- •The Image Object
- •Exchanging Images through the Clipboard
- •Drawing with GDI+
- •The Basic Drawing Objects
- •Drawing Shapes
- •Drawing Methods
- •Gradients
- •Coordinate Transformations
- •Specifying Transformations
- •VB.NET at Work: Plotting Functions
- •Bitmaps
- •Specifying Colors
- •Defining Colors
- •Processing Bitmaps
- •Summary
- •The Printing Objects
- •PrintDocument
- •PrintDialog
- •PageSetupDialog
- •PrintPreviewDialog
- •PrintPreviewControl
- •Printer and Page Properties
- •Page Geometry
- •Printing Examples
- •Printing Tabular Data
- •Printing Plain Text
- •Printing Bitmaps
- •Using the PrintPreviewControl
- •Summary
- •Examining the Advanced Controls
- •How Tree Structures Work
- •The ImageList Control
- •The TreeView Control
- •Adding New Items at Design Time
- •Adding New Items at Runtime
- •Assigning Images to Nodes
- •Scanning the TreeView Control
- •The ListView Control
- •The Columns Collection
- •The ListItem Object
- •The Items Collection
- •The SubItems Collection
- •Summary
- •Types of Errors
- •Design-Time Errors
- •Runtime Errors
- •Logic Errors
- •Exceptions and Structured Exception Handling
- •Studying an Exception
- •Getting a Handle on this Exception
- •Finally (!)
- •Customizing Exception Handling
- •Throwing Your Own Exceptions
- •Debugging
- •Breakpoints
- •Stepping Through
- •The Local and Watch Windows
- •Summary
- •Basic Concepts
- •Recursion in Real Life
- •A Simple Example
- •Recursion by Mistake
- •Scanning Folders Recursively
- •Describing a Recursive Procedure
- •Translating the Description to Code
- •The Stack Mechanism
- •Stack Defined
- •Recursive Programming and the Stack
- •Passing Arguments through the Stack
- •Special Issues in Recursive Programming
- •Knowing When to Use Recursive Programming
- •Summary
- •MDI Applications: The Basics
- •Building an MDI Application
- •Built-In Capabilities of MDI Applications
- •Accessing Child Forms
- •Ending an MDI Application
- •A Scrollable PictureBox
- •Summary
- •What Is a Database?
- •Relational Databases
- •Exploring the Northwind Database
- •Exploring the Pubs Database
- •Understanding Relations
- •The Server Explorer
- •Working with Tables
- •Relationships, Indices, and Constraints
- •Structured Query Language
- •Executing SQL Statements
- •Selection Queries
- •Calculated Fields
- •SQL Joins
- •Action Queries
- •The Query Builder
- •The Query Builder Interface
- •SQL at Work: Calculating Sums
- •SQL at Work: Counting Rows
- •Limiting the Selection
- •Parameterized Queries
- •Calculated Columns
- •Specifying Left, Right, and Inner Joins
- •Stored Procedures
- •Summary
- •How About XML?
- •Creating a DataSet
- •The DataGrid Control
- •Data Binding
- •VB.NET at Work: The ViewEditCustomers Project
- •Binding Complex Controls
- •Programming the DataAdapter Object
- •The Command Objects
- •The Command and DataReader Objects
- •VB.NET at Work: The DataReader Project
- •VB.NET at Work: The StoredProcedure Project
- •Summary
- •The Structure of a DataSet
- •Navigating the Tables of a DataSet
- •Updating DataSets
- •The DataForm Wizard
- •Handling Identity Fields
- •Transactions
- •Performing Update Operations
- •Updating Tables Manually
- •Building and Using Custom DataSets
- •Summary
- •An HTML Primer
- •HTML Code Elements
- •Server-Client Interaction
- •The Structure of HTML Documents
- •URLs and Hyperlinks
- •The Basic HTML Tags
- •Inserting Graphics
- •Tables
- •Forms and Controls
- •Processing Requests on the Server
- •Building a Web Application
- •Interacting with a Web Application
- •Maintaining State
- •The Web Controls
- •The ASP.NET Objects
- •The Page Object
- •The Response Object
- •The Request Object
- •The Server Object
- •Using Cookies
- •Handling Multiple Forms in Web Applications
- •Summary
- •The Data-Bound Web Controls
- •Simple Data Binding
- •Binding to DataSets
- •Is It a Grid, or a Table?
- •Getting Orders on the Web
- •The Forms of the ProductSearch Application
- •Paging Large DataSets
- •Customizing the Appearance of the DataGrid Control
- •Programming the Select Button
- •Summary
- •How to Serve the Web
- •Building a Web Service
- •Consuming the Web Service
- •Maintaining State in Web Services
- •A Data-Driven Web Service
- •Consuming the Products Web Service in VB
- •Summary

378 Chapter 8 BUILDING CUSTOM CLASSES
to the base class. In a drawing application, all shapes have an outline and a fill color. These properties can be implemented in the Shape class, because they apply to all derived classes. Any methods with common implementation for all classes should also be implemented as methods of the parent class.
The same techniques can be applied to more elaborate classes. For example, you can create a class that represents persons and then derive any number of classes from the Person class. The derived classes could be the Employee class, the Salesperson class, the Consultant class, and so on. The Person class stores the information that is common to all persons, and each of the derived classes inherits these properties and methods. The Pay method can’t be common to all persons, and it must be implemented in each individual class. Some persons are paid a salary, others are paid commissions, and so on. The individual methods of each class must implement the Pay method according to the type of person they represent. Inheritance pays off in very large projects, while it may introduce substantial complications in small projects, especially if used without careful design.
Object Constructors and Destructors
As you already know, objects are created and then disposed of when no longer needed. To construct an object, you must first declare it and then set it to a new instance of the class it represents. To construct a triangle, for example, you can use either of these two statements:
Dim shape1 As Triangle = New Triangle()
Dim shape1 As New Triangle()
It is also possible to specify the properties of an object in the same line that creates the object, with the New keyword. This is the object’s constructor (it initializes the object by setting some or all of its properties).
Dim rect1 As Rectangle = New Rectangle(10, 10, 50, 90)
The shapes in the Shapes class can’t be initialized in the same line that declares them, because they don’t provide a constructor. We must implement a so-called parameterized constructor, which allows you to pass arguments to an object as you declare it. These arguments are usually the basic properties of the object. Parameterized constructors don’t pass arguments for all the properties of the object; they expect only enough parameter values to make the object usable.
Constructors are implemented with the New subroutine, which is called every time a new instance of the class is initialized. This is where you code initialization tasks such as opening files and establishing connections to databases. We used the New subroutine to instantiate a new Timer object in an earlier example. This time, we’ll create a New subroutine for each shape, and we’ll declare arguments for the New subroutine.
VB6 VB.NET
The Class_Initialize method of VB6 has been replaced by the New subroutine, and the Class_Terminate method of VB6 has been replaced by the Destruct subroutine in VB.NET.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

POLYMORPHISM 379
Let’s start with the Triangle class. When we initialize a Triangle, we want to be able to specify the sides of the triangle. Here’s the constructor for the Triangle class:
Sub New(ByVal sideA As Double, ByVal sideB As Double, ByVal sideC As Double) MyBase.New()
side1 = sideA side2 = sideB side3 = sideC
End Sub
The code is quite trivial, with the exception of the statement that calls the MyBase.New subroutine. MyBase is a keyword that lets you access the members of the base class (a topic that’s discussed in detail later in this chapter). The reason you must call the New method of the base class is that the base class may have its own constructor, which can’t be called directly. You must always insert this statement in your constructors to make sure that any initialization tasks that must be performed by the base class will not be skipped.
Likewise, when we create a Circle object, we want to be able to specify its radius. The following is the parameterized constructor of the Circle class:
Sub New(ByVal radius As Double) MyBase.New()
cRadius = radius End Sub
When you enter a statement like
Dim shape1 As New Triangle(
in the editor, you will see a list of the parameters you can set, as shown in Figure 8.11.
Figure 8.11
The members of the various Shape constructors displayed by IntelliSense
If you no longer need an object, you can set it to Nothing. The Common Language Runtime (CLR) won’t release the object as soon as you set it to Nothing. The new garbage collector (GC) checks periodically for objects that are no longer needed and releases them. However, you don’t know when this will happen. If there are tasks you want to perform prior to releasing an object, place them in the Destruct subroutine. The GC will call this subroutine (if it exists) prior to releasing the object.
The New() subroutine is usually overloaded. We always provide a constructor that accepts no arguments, so that developers can create an instance of the class without having to specify any of the arguments. The following New() constructor allows you to create an instance of the Triangle shape without passing any parameters:
Sub New()
MyBase.New()
End Sub
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

380 Chapter 8 BUILDING CUSTOM CLASSES
You may have noticed the lack of the Overloads keyword. Constructors can have multiple forms and don’t require the use of Overloads—just supply as many implementations of the New() subroutine as you need. The following statements show how to create three overloaded forms of the New constructor of the Circle shape. The first constructor accepts no arguments, the second constructor accepts the radius of the circle, and the last constructor accepts a Rectangle object that encloses the circle:
Sub New() MyBase.New()
End Sub
Sub New(ByVal radius As Double) MyBase.New()
cRadius = radius End Sub
Sub New(ByVal rect As Rectangle) MyBase.New()
cRadius = rect.Width End Sub
Instance and Shared Methods
As you may have noticed in previous chapters (and it will become even more clear in the following chapters), some classes allow you to call some of their members without first creating an instance of the class. The String class, for example, exposes the IsLeapYear method, which accepts as argument a numeric value and returns a True/False value indicating whether the year is leap or not. You can call this method through the DateTime (or Date) class, as shown in the following statement:
If DateTime.IsLeapYear(1999) Then
{ process a leap year }
End If
Other members, like the Day property, can’t be called through the name of the class. You must first create an instance of the DateTime class, assign a value to it, and then call the Day method of the specific instance of the class. The Day property returns the number of the day, and it has meaning only when applied to a specific date. To call the Day property, declare a variable of the Date type, initialize it, and then call its Day property:
Dim d1 As Date = Now()
Console.WriteLine(d1.Day)
If you attempt to call the property Date.Day, the statement will not be compiled and the error message will be “Day is not a member of Date.” The methods that don’t require that you create an instance of the class before you call them are called shared methods. Methods that can be applied to an instance of the class are called instance methods. By default, all methods are instance methods. To create a shared method, you must prefix the corresponding function declaration with the Shared keyword, just like a shared property.
Why do we need a shared method, and when should we create shared methods? If a method doesn’t apply to a specific instance of a class, make it shared. Let’s consider the DateTime class, which implements the Date data type. The DaysInMonth methods returns the number of days in
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

POLYMORPHISM 381
the month that was passed to the method as argument. You don’t really need to create an instance of a Date object to retrieve the current date, so the DaysInMonth method is a shared method. The AddDays method, on the other hand, is an instance method. We have a date to which we want to add a number days and construct a new date. In this case, it makes sense to apply the method to an instance of the class—the instance that represents the date to which we add the number of days.
The SharedMembers project on the CD is a simple class that demonstrates the differences between a shared and an instance method. Both methods do the same thing: they reverse the characters in a string. The IReverseString method is an instance method: it reverses the current instance of the class, which is a string. The SReverseString method is a shared method: it reverses its argument. Listing 8.40 shows the code that implements the SharedMembersClass component.
Listing 8.40: A Class with a Shared and an Instance Method
Public Class SharedMembersClass Private strProperty As String Sub New(ByVal str As String)
strProperty = str End Sub
Public Function IReverseString() As String Return (StrReverse(strProperty))
End Function
Public Shared Function SReverseString(ByVal str As String) As String Return (StrReverse(str))
End Function End Class
The instance method acts on the current instance of the class. This means that the class must be initialized to a string, and this is why the New constructor requires a string argument. To test the class add a form to the project, make it the Startup object and add two buttons on it. The code behind the two buttons is shown next:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim testString As String = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”
Dim obj As New SharedMembersClass(testString)
Console.WriteLine(obj.IReverseString)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim testString As String = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”
Console.WriteLine(SharedMembersClass.SReverseString(testString))
End Sub
The code behind the first button creates a new instance of the SharedMembersClass and calls its IReverseString method. The second button calls the SReverseString method through the class’s name and passes the string to be reversed as argument to the method.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |