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

484 Chapter 11 STORING DATA IN COLLECTIONS
Another form of the Sort method uses a user-supplied function to sort arrays of custom objects. As you recall, arrays can store all types of objects. But the Framework doesn’t know how to sort your custom objects. To sort an array of objects, you must provide your own function that implements the IComparer interface. This form of the Sort method is described in detail in the later section “The IEnumerator and IComparer Interfaces,” where you will also learn how to write functions for sorting your custom objects.
Searching Arrays
Arrays can be searched in two ways: with the BinarySearch method, which works on sorted arrays and is extremely fast; and with the IndexOf (and LastIndexOf) methods, which work regardless of the order of the elements. All three methods search for an instance of an item and return its index. The IndexOf and LastIndexOf methods are similar to the methods by the same name of the String class. They return the index of the first (or last) instance of an object in the array, or the value –1 if the object isn’t found in the array. Both methods are overloaded, and the simplest form of the IndexOf method is:
itemIndex = System.Array.IndexOf(array, object)
where array is the name of the array to be searched and object is the item you’re searching for. The LastIndexOf method’s syntax is identical, but the LastIndexOf method starts searching from the end of the array. If the item you’re searching for is unique in the array, both methods will return the same index.
Another form of the IndexOf and LastIndexOf methods allows you to begin the search at a specific index:
itemIndex = System.Array.IndexOf(array, object, startIndex)
This form of the method starts searching in the segment of the array from startIndex to the end of the array. Finally, you can specify the range of indices where the search will take place with the following form of the method:
itemIndex = System.Array.IndexOf(array, object, startIndex, endIndex)
You can search large arrays more efficiently with the BinarySearch method, if the array is sorted. The simplest form of the BinarySearch method is
System.Array.BinarySearch(array, object)
where array is the name of the array and object the item you’re searching for. To search a section of the array, supply the two indices that delimit the section of the array you wish to sort:
System.Array.BinarySearch(array, startIndex, selLength, object)
If the array contains custom objects, you must provide an IComparer object that compares two elements. This is the same object you supply to the Sort method for custom sorts.
The BinarySearch method returns an integer value, which is the index of the object you’re searching for in the array. If the object argument is not found, the method returns a negative value, which is the negative of the index of the next larger item minus one. This transformation, the negative of a positive number minus one, is called the one’s complement, and other languages provide an operator for it, the tilde (~). The one’s complement of 10 is –11, and the one’s complement of –3 is 2.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

ADVANCED ARRAY TOPICS 485
Why all this complexity? Zero is a valid index, so only a negative value could indicate a failure in the search operation. A value of –1 would indicate that the operation failed, but the BinarySearch method does something better. If it can’t locate the item, it returns the index of the item immediately after the desired item (the first item in the array that exceeds the item you’re searching for). This is a near match, and the BinarySearch method returns a negative value to indicate near matches. Notice that there will always be a near match, unless you’re searching for a value larger than the last value in the array. In this case, the BinarySearch method will return the one’s complement of the array’s upper bound. If your array was declared with 100 elements and the value you’re searching for is an element that’s larger than the last element, the BinarySearch method will return the one’s complement of the value 100 (which is –101).
Tip Like the BinarySearch method, the IndexOf and LastIndexOf methods perform case-sensitive searches. However, because the BinarySearch method reports near matches, it appears as if it performs case-insensitive searches. If the array contains the element “Charles” and you search for “charles,” the IndexOf method will not find the string, while the BinarySearch will find it but will report it as a near match.
The Option Compare statement has no effect on the comparisons performed either by the BinarySearch or by the IndexOf/LastIndexOf methods. If you want to perform case-insensitive comparisons, you must provide your own custom comparer, as described in the section “Custom Sorting,” later in this chapter.
The ArraySearch application, shown in Figure 11.2, demonstrates how to handle exact and near matches reported by the BinarySearch method. The Populate Array button populates an array with 1,000 random strings. The same strings are also displayed on a sorted ListBox control, so that you can view them. The elements have the same order in both the array and the ListBox, so we can use the index reported by the BinarySearch method to locate and select instantly the same item in the ListBox.
Figure 11.2
Searching an array and locating the same element in the ListBox control
The Populate Array button creates 1,000 random strings, each with a length of 3 to 15 characters. Both the length of each string and the characters in it are chosen randomly. You can find the code of the Populate Array button’s Click handler on the CD. This isn’t the most interesting part of the application anyway. When you run the application, message boxes will pop up displaying the
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

486 Chapter 11 STORING DATA IN COLLECTIONS
time it took for each operation: how long it took to populate the array, how long it took to sort it, and how long it took to populate the ListBox. You may wish to experiment with large arrays (100,000 elements or more).
The Search Array button prompts the user for a string with an InputBox and then locates the string with the BinarySearch method in the array. The result is either an exact or a near match, and it’s displayed on a message box. At the same time, the item reported by the BinarySearch method is also selected in the ListBox control.
To test the application, find a string in the list and then click the Search Array button. Enter the entire string (you can use lowercase or uppercase characters; it doesn’t make a difference) and verify that the application reports an exact match and locates the item in the ListBox. Then enter a string that doesn’t exist in the list (or the beginning of an existing string) and see how the BinarySearch handles near matches.
The code behind the Search Array button calls the BinarySearch method and stores the integer returned by the method to the wordIndex variable. Then it examines the value of this variable. If wordIndex is positive, there was an exact match and it’s reported. If wordIndex is negative, the program calculates the one’s complement of this value, which is the index of the near match. The element at this index is reported as a near match. Finally, regardless of the type of the match, the code selects the same item in the ListBox and makes it visible. Listing 11.2 is the code behind the Search Array button.
Listing 11.2: Locating Exact and Near Matches with BinarySearch
Private Sub bttnSearch_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bttnSearch.Click Dim srchWord As String
Dim wordIndex As Integer
srchWord = InputBox(“Enter word to search for”) wordIndex = System.Array.BinarySearch(words, srchWord) Console.WriteLine(wordIndex)
If wordIndex >= 0 Then
MsgBox(“Words(“ & wordIndex.ToString & “) = “ & _ words(wordIndex), , “EXACT MATCH”)
ListBox1.TopIndex = wordIndex ListBox1.SelectedIndex = wordIndex
Else
MsgBox(“Words(“ & (-wordIndex - 1).ToString & “) = “ & _ words(-wordIndex - 1), , “NEAR MATCH”)
ListBox1.TopIndex = -wordIndex - 1 ListBox1.SelectedIndex = -wordIndex - 1
End If End Sub
Notice that all methods for sorting and searching arrays work with the base data types only. If the array contains custom data types, you must supply your own functions for comparing elements of this type, a process described in detail in the section “The IEnumerator and IComparer Interfaces,” later in this chapter.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |

ADVANCED ARRAY TOPICS 487
The Binary Search Algorithm
The BinarySearch method uses a very powerful search algorithm, the binary search algorithm, but it requires that the array be sorted. You need not care about the technical details of the implementation of a method, but in the case of the binary search algorithm, a basic understanding of how it works will help you understand how it performs near matches. To locate an item in a sorted array, this method compares the search string to the array’s middle element. If the search string is smaller, we know that the element is in the first half of the array and we can safely ignore the second half. The same process is repeated with the remaining half of the elements. The search string is compared to the middle element of the reduced array, and after the comparison, we can ignore one half of the reduced array. At each step, the binary search algorithm rejects one half of the items left until it reduces the list to a single item. This is the item we’re searching for. If not, the item is not in the list. To search a list with 1,024 items, the binary search algorithm makes 10 comparisons. At the first step, it rejects 512 elements, then 256, then 128 and so on, until it reaches a single element. For an array of 1,024 × 1,024 (that’s a little more than a million) items, the algorithm makes 20 comparisons to locate the desired item.
If you apply the BinarySearch method on an array that hasn’t been sorted, the method will carry out all the steps and report that the item wasn’t found, even though it may be in the array. The algorithm doesn’t check the order of the elements; it just assumes that they’re sorted. You may also have noticed that, regardless of the outcome, the same number of operations takes place. The binary search algorithm always halves the number of elements in which it attempts to locate the desired element in the array. That’s why you should never apply to the BinarySearch method to an array that hasn’t been sorted yet.
To see what happens when you apply the BinarySearch method to an array that hasn’t been sorted, remove the statement that calls the Sort method in the ArraySearch sample application. The application will keep reporting near matches, even if the string you’re searching is present in the array. The BinarySearch method, assuming that the array is sorted, keeps halving the array by successive comparisons. When it’s left with a single item, which is not the one you’re searching for, it returns the index of the following element and reports a near match. Of course, the near match isn’t close to the element you’re searching for by any stretch of the word—it’s an element that happens to be there when the algorithm finishes. You should never apply the BinarySearch method to an array that hasn’t been sorted.
Sorting an array is an expensive operation, and you can’t afford to continuously sort lengthy arrays. If your array isn’t sorted, you can still search for specific items with the IndexOf and LastIndexOf methods. These methods locate an item in an array and they’re overloaded, similar to the BinarySearch method.
Other Array Operations
The Array class exposes additional methods, which are described briefly in this section.
The Reverse method reverses the order of the elements in an array. The syntax of the Reverse method is
System.Array.Reverse(array)
The Reverse method can’t be applied to an array and reverse its elements. Instead, it returns a new array with the elements of the array passed as argument, only in reverse order. To reverse the order of
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |