
- •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

340 Chapter 8 BUILDING CUSTOM CLASSES
The statements of Listing 8.9 will produce the following output:
They’re equal
They’re equal
The two variables are initially equal. No surprise. After modifying one of the obj2 variable’s properties, however, they’re still equal, because obj2 points to obj1. Every time we change obj2, obj1 also changes. That’s because we’ve made obj1 point to obj2. They both point to the same object (or instance of the class), and you can access this object through either class.
Comment out the line that sets obj2 equal to obj1. Now, they’re not equal, even if you set all their fields to the same values. They don’t reference the same object, and it’s possible to set their properties differently.
In the following section, we’ll add an Equals method that checks for value equality (as opposed to reference equality) by comparing the values of the properties of the two instances.
Customizing Default Members
As you recall, when you created the Minimal class for the first time, before adding any code, the class already exposed a few members—the default members, such as the ToString method (which returns the name of the class) and the Equals method (which compares two objects for reference equality). You can provide your custom implementation for these members; this is what we’re going to do in this section. You already know how to do this. Your custom ToString method must be implemented as a public function, and it must override the default implementation. The implementation of a custom ToString method is shown next:
Public Overrides Function ToString() As String
Return “The infamous Minimal class”
End Function
It’s that simple. The Overrides keyword tells the compiler that this implementation overwrites the default implementation of the class. Ours is a very simple method, but you can return any string you can build in the function. For example, you can incorporate the value of the BDate property in the string:
Return(“MINIMAL: “ & tBDate.ToString)
tBDate is a local variable in the class’s module, and you can use its value in any way you see fit in your code. The value of the local variable tBDate is the current value of the BDate property of the current instance of the class.
When called through different variables, the ToString method will report different values. Let’s say you’ve created and initialized two instances of the Minimal class with the following statements:
Dim obj1 As New Minimal()
Obj1.Bdate = #1/1/1963#
Dim obj2 As New Minimal()
Obj2.Bdate = #12/31/1950#
Console.WriteLine(obj1.ToString)
Console.WriteLine(obj2.ToString)
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

BUILDING THE MINIMAL CLASS 341
The last two statements will print the following lines on the Output window:
MINIMAL: 1963-01-01 00:00:00
MINIMAL: 1950-12-31 00:00:00
The Equals method exposed by most of the built-in objects, however, can compare values, not references. Two Rectangle objects, for example, are equal if their dimensions and origins are the same. The following two rectangles are equal:
Dim R1 As New Rectangle(0, 0, 30, 60)
Dim R2 As New Rectangle
R2.X = 0
R2.Y = 0
R2.Width = 30
R2.Height = 60
If R1.Equals(R2) Then
MsgBox(“The Two rectangles are equal”)
End If
If you execute these statements, a message box will pop up. The two variables point to different objects (i.e., different instances of the same class), but the two objects are equal. The Rectangle class provides its own Equals method, which knows how to compare two Rectangle objects. If your class doesn’t provide a custom Equals method, all the compiler can do is compare the objects referenced by the two variables. In the case of our Minimal class, the Equals method returns True if the two variables point to the same object (which is the same instance of the class). If the two variables point to two different objects, the default Equals method will return False, even if the two objects are equal.
You’re probably wondering what makes two objects equal. Is it all of their properties, or perhaps some of them? Two objects are equal if the Equals method says so. You should compare the objects in a way that makes sense, but you’re in no way limited as to how you do this. You may even compare internal variables that are not exposed as properties to decide about the equality. In the Minimal class, for example, you may decide to compare the birth dates and return True if they’re equal. Listing 8.10 is the implementation of a possible custom Equals method for the Minimal class.
Listing 8.10: A Custom Equals Method
Public Overloads Function Equals(ByVal obj As Object) As Boolean
Dim O As Minimal = CType(obj, Minimal)
If O.BDate = tBDate Then
Equals = True
Else
Equals = False
End If
End Function
Notice that the Equals method is prefixed with the Overloads keyword, not the Overrides keyword. To test the new Equals method, place a new button on the form and insert the statements of Listing 8.11 in its Click event handler.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

342 Chapter 8 BUILDING CUSTOM CLASSES
Listing 8.11: Testing the Custom Equals Method
Dim O1 As New Minimal()
Dim O2 As New Minimal()
O1.BDate = #3/1/1960#
O2.BDate = #3/1/1960#
O1.property1 = “object1”
O2.property1 = “OBJECT2”
If O1.Equals(O2) Then
MsgBox(“They’re equal”)
End If
If you run the application, you’ll see the message confirming that the two objects are equal, despite the fact that their property1 properties were set to different values. The BDate property is the same, and this is the only setting the Equals method examines.
So, it’s up to you to decide which properties fully and uniquely identify an object and to use these properties in determining when two objects are equal. It’s customary to compare the values of all the properties of the two objects in the Equals function and return True if they’re all the same. You can modify the code of the custom Equals function to take into consideration the other properties.
Know What You’re Comparing
The Equals method shown in Listing 8.10 assumes that the object you’re trying to compare to the current instance of the class is of the same type. Since you can’t rely on developers to catch all their mistakes, you should know what you’re comparing before you actually do the comparison. A more robust implementation of the Equals method is shown in Listing 8.12.
Listing 8.12: A More Robust Equals Method
Public Overloads Function Equals(ByVal obj As Object) As Boolean
Dim O As New Minimal()
Try
O = CType(obj, Minimal)
Catch typeExc As InvalidCastException
Throw typeExc
Exit Function
End Try
If O.BDate = tBDate Then
Equals = True
Else
Equals = False
End If
End Function
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

BUILDING THE MINIMAL CLASS 343
Note Note that the custom Equals method throws the same exception it receives from the CType() function. This is a little different from creating and throwing a new custom exception, as we did in the Age property’s code.
Custom Enumerations
Let’s add a little more complexity to our class. Since we’re storing dates of birth to our class, we can classify persons according to their age. Instead of using literals to describe the various age groups, we’ll use an enumeration, with the following group names:
Public Enum AgeGroup
Baby
Child
Teenager
Adult
Senior
Overaged
End Enum
These statements must appear outside any procedure in the class, and we usually place them at the beginning of the file, right after the declaration of the Class. The enumeration is a list of integer values, each one mapped to a name. In our example, the name Baby corresponds to 0, the name Child corresponds to 1, and so on. You don’t really care about the actual values of the names, because the very reason for using enumerations is to replace numeric constants with more meaningful names. You’ll see shortly how enumerations are used both in the class and the calling application.
Now add to the class the GetAgeGroup method (Listing 8.13), which returns the name of the group to which the person represented by an instance of the Minimal class belongs. The name of the group is a member of the AgeGroup enumeration.
Listing 8.13: Using an Enumeration
Public Function GetAgeGroup() As AgeGroup
Dim group As AgeGroup
Select Case tAge
Case Is < 5 : Return (group.Baby)
Case Is < 12 : Return (group.Child)
Case Is < 21 : Return (group.Teenager)
Case Is < 65 : Return (group.Adult)
Case Is < 100 : Return (group.Senior)
Case Else : Return (group.Overaged)
End Select
End Function
First, we declare a variable of the AgeGroup type. As you can see, the members of the AgeGroup enumeration become properties of the group variable. The advantage of using enumerations is that you can manipulate meaningful names instead of numeric constants. This makes your code less prone to errors and far easier to understand.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |