- •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
ARGUMENTS 177
The function’s return type is Double(), meaning the function will return an array of doubles; that’s what the empty parentheses signify. This array is declared in the function’s body with the statement:
Dim Result(3) As Double
The function performs its calculations and then assigns the values of the basic statistics to the elements of the array Result. The first element holds the average, the second element holds the standard deviation, and the other two elements hold the minimum and maximum data values. The Result array is finally returned to the calling procedure by the statement that assigns the array to the function name, just as you’d assign a variable to the name of the function that returns a single result.
The code behind the Calculate Statistics button, which calls the ArrayStats() function, is shown in Listing 4.3.
Listing 4.3: Calculating Statistics with the ArrayStats() Function
Protected Sub Button2_Click(ByVal sender As Object, _ ByVal e As System.EventArgs)
Dim SData(99) As Double Dim Stats() As Double Dim i As Integer
Dim rnd As New System.Random() ListBox1.Items.Clear()
For i = 0 To 99
SData(i) = rnd.NextDouble() * 1000 ListBox1.Items.Add(SData(i))
Next
Stats = ArrayStats(SData)
TextBox1.Text = “Average” & vbTab & vbTab & Stats(0)
TextBox1.Text = TextBox1.Text & cvCrLf & “Std. Deviation” & vbTab & Stats(1) TextBox1.Text = TextBox1.Text & vbCrLf & “Min. Value” & vbTab & Stats(2) TextBox1.Text = TextBox1.Text & vbCrLf & “Max. Value” & vbTab & Stats(3)
End Sub
The code generates 100 random values and displays them on a ListBox control. Then, it calls the ArrayStats() function, passing the data values to it through the SData array. The function’s return values are stored in the Stats array, which is declared as double but without dimensions. Then, the code displays the basic statistics on a TextBox control, one item per line.
Overloading Functions
There are situations where the same function must operate on different data types, or a different number of arguments. In the past, you had to write different functions, with different names and different arguments, to accommodate similar requirements. VB.NET introduces the concept of function overloading, which means that you can have multiple implementations of the same function, each with a different set of arguments and, possibly, a different return value. Yet, all overloaded functions share the same name. Let me introduce this concept by examining one of the many overloaded functions that come with the .NET Framework.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
178 Chapter 4 WRITING AND USING PROCEDURES
To generate a random number in the range from 0 to 1 (exclusive), use the NextDouble method of the System.Random class. To use the methods of the Random class, you must first create an instance of the class and then call the methods:
Dim rnd As New System.Random Console.WriteLine(“Three random numbers”)
Console.Write(rnd.NextDouble() & “ – “ & rnd.NextDouble() & “ – “ & _ rnd.NextDouble())
The random numbers that will be printed on the Output window will be double precision values in the range 0 to 1:
0.656691639058614 – 0.967485965680092 – 0.993525570721145
More often than not, we need integer random values. The Next method of the System.Random class returns an integer value from –2,147,483,648 to 2,147,483,647 (this is the range of values that can be represented by the Integer data type). We also want to generate random numbers in a limited range of integer values. To emulate the throw of a dice, we want a random value in the range from 1 to 6, while for a roulette game we want an integer random value in the range from 0 to 36. You can specify an upper limit for the random number with an optional integer argument. The following statement will return a random integer in the range from 0 to 99:
randomInt = rnd.Next(100)
Finally, you can specify both the lower and upper limits of the random number’s range. The following statement will return a random integer in the range from 1,000 to 1,999:
randomInt = rnd.Next(1000, 2000)
The same method behaves differently based on the arguments we supply. The behavior of the method depends either on the type of the arguments, the number of the arguments, or both of them. As you will see, there’s no single function that alters its behavior based on its arguments. There are as many different implementations of the same function as there are argument combinations. All the functions share the same name, so that they appear to the user as a single, multifaceted function. These functions are overloaded, and you’ll see in the following section how they’re implemented.
If you haven’t turned off the IntelliSense feature of the editor, then as soon as you type the opening parenthesis after a function or method name, you see a yellow box with the syntax of the function or method. You’ll know that a function is overloaded when this box contains a number and two arrows. Each number corresponds to a different overloaded form, and you can move to the next or previous overloaded form by clicking the two little arrows or by pressing the arrow keys.
Let’s return to the Min() function we implemented earlier in this chapter. The initial implementation of the Min() function is shown next:
Function Min(ByVal a As Double, ByVal b As Double) As Double
Min = IIf(a < b, a, b)
End Function
By accepting double values as arguments, this function can handle all numeric types. VB.NET performs automatically widening conversions (it can convert integers and decimals to doubles), so this trick makes our function work with all numeric data types. However, what about strings? If you
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
ARGUMENTS 179
attempt to call the Min() function with two strings as arguments, you’ll get an exception. The Min() function just can’t handle strings.
To write a Min() function that can handle both numeric and string values, you must, in essence, write two Min() functions. All Min() functions must be prefixed with the Overloads keyword. The following statements show two different implementations of the same function:
Overloads Function Min(ByVal a As Double, ByVal b As Double) As Double Min = IIf(a < b, a, b)
End Function
Overloads Function Min(ByVal a As String, ByVal b As String) As String Min = IIf(a < b, a, b)
End Function
As you may have guessed, we need a third overloaded form of the same function to compare dates. If you call the Min() function with two dates are arguments, as in the following statement, the Min() function will compare them as strings.
Console.WriteLine(Min(#1/1/2001#, #3/4/2000#))
This statement will print the date 1/1/2001, which is not the smaller (earlier) date. If you swap the years and call the function as
Console.WriteLine(Min(#1/1/2000#, #3/4/2001#))
you’ll get the earlier date, but just because it happens that their alphanumeric order is now the same as their chronological order.
The overloaded form of the function that accepts dates as arguments is shown next:
Overloads Function Min(ByVal a As Date, ByVal b As Date) As Date
Min = IIf(a < b, a, b)
End Function
If you now call the Min() function with the dates #1/1/2001# and #3/4/2000#, the function will return the second date, which is chronologically smaller than the first.
OK, the example of the Min() function is rather trivial. You can also write a Min() function that compares two objects and handle all other data types. Let’s look into a more complicated overloaded function, which makes use of some topics discussed later in this book. The CountFiles() function counts the number of files that meet certain criteria. The criteria could be the size of the files, their type, or the date they were created. You can come up with any combination of these criteria, but here are the most useful combinations. (These are the functions I would use, but you can create even more combinations, or introduce new criteria of your own.) The names of the arguments are selfdescriptive, so I need not explain what each form of the CountFiles() function does.
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer) As Integer CountFiles(ByVal fromDate As Date, ByVal toDate As Date) As Integer CountFiles(ByVal type As String) As Integer
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer, _ ByVal type As String) As Integer
CountFiles(ByVal fromDate As Date, ByVal toDate As Date, _ ByVal type As String) As Integer
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
180 Chapter 4 WRITING AND USING PROCEDURES
Listing 4.4 shows the implementation of these overloaded forms of the CountFiles() function. Since we haven’t discussed files yet, most of the code in the function’s body will be new to you—but it’s not hard to follow. For the benefit of readers who are totally unfamiliar with file operations, I’ve included a statement that prints on the Output window the type of files counted by each function. The Console.WriteLine statement prints the values of the arguments passed to the function, along with a description of the type of search it’s going to perform. The overloaded form that accepts two integer values as arguments prints something like:
You’ve requested the files between 1000 and 100000 bytes
while the overloaded form that accepts a string as argument prints the following:
You’ve requested the .EXE files
Listing 4.4: The Overloaded Implementations of the CountFiles() Function
Overloads Function CountFiles(ByVal minSize As Integer, _
ByVal maxSize As Integer) As Integer Console.WriteLine(“You’ve requested the files between “ & minSize & _
“ and “ & maxSize & “ bytes”) Dim files() As String
files = System.IO.Directory.GetFiles(“c:\windows”) Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i))
If FI.Length >= minSize And FI.Length <= maxSize Then fileCount = fileCount + 1
End If Next
Return(fileCount) End Function
Overloads Function CountFiles(ByVal fromDate As Date, _
ByVal toDate As Date) As Integer Console.WriteLine(“You’ve requested the count of files created from “ & _
fromDate & “ to “ & toDate) Dim files() As String
files = System.IO.Directory.GetFiles(“c:\windows”) Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i)) If FI.CreationTime.Date >= fromDate And _ FI.CreationTime.Date <= toDate Then
fileCount = fileCount + 1 End If
Next Return(fileCount)
End Function
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
ARGUMENTS 181
Overloads Function CountFiles(ByVal type As String) As Integer Console.WriteLine(“You’ve requested the “ & type & “ files”) Dim files() As String
files = System.IO.Directory.GetFiles(“c:\windows”) Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i)) If FI.Extension = type Then
fileCount = fileCount + 1 End If
Next Return(fileCount)
End Function
Overloads Function CountFiles(ByVal minSize As Integer, _
ByVal maxSize As Integer, ByVal type As String) As Integer Console.WriteLine(“You’ve requested the “ & type & “ files between “ & _
minSize & “ and “ & maxSize & “ bytes”) Dim files() As String
files = System.IO.Directory.GetFiles(“c:\windows”) Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i)) If FI.Length >= minSize And _
FI.Length <= maxSize And _ FI.Extension = type Then
fileCount = fileCount + 1 End If
Next Return(fileCount)
End Function
Overloads Function CountFiles(ByVal fromDate As Date, ByVal toDate As Date, _ ByVal type As String) As Integer
Console.WriteLine(“You’ve requested the “ & type & _
“ files created from “ & fromDate & “ to “ & toDate) Dim files() As String
files = System.IO.Directory.GetFiles(“c:\windows”) Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i)) If FI.CreationTime.Date >= fromDate And _
FI.CreationTime.Date <= toDate And FI.Extension = type Then fileCount = fileCount + 1
End If Next
Return(fileCount) End Function
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
182 Chapter 4 WRITING AND USING PROCEDURES
If you’re unfamiliar with the Directory and File objects, focus on the statement that prints to the Output window and ignore the statements that actually count the files that meet the specified criteria. After reading Chapter 13, you can revisit this example and understand the counting statements. The Console.WriteLine statements report all the values passed as arguments, and they differentiate between the various overloaded forms of the function.
Start a new project and enter the definitions of the overloaded forms of the function on the form’s level. Listing 4.4 is lengthy, but all the overloaded functions have the same structure and differ only in how they select the files to count. Then place a TextBox and a button on the form, as shown in Figure 4.4, and enter the statements from Listing 4.5 in the button’s Click event handler. The project shown in Figure 4.4 is called OverloadedFunctions, and you’ll find it in this chapter’s folder on the CD.
Figure 4.4
The Overloaded-
Functions project
Listing 4.5: Testing the Overloaded Forms of the CountFiles() Function
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click TextBox1.AppendText(CountFiles(1000, 100000) & _
“ files with size between 1KB and 100KB” & vbCrLf) TextBox1.AppendText(CountFiles(#1/1/2001#, #12/31/2001#) & _
“ files created in 2001” & vbCrLf) TextBox1.AppendText(CountFiles(“.BMP”) & “ BMP files” & vbCrLf) TextBox1.AppendText(CountFiles(1000, 100000, “.EXE”) & _
“ EXE files between 1 and 100 KB” & vbCrLf) TextBox1.AppendText(CountFiles(#1/1/2000#, #12/31/2001#, “.EXE”) & _
“ EXE files created in 2000 and 2001”)
End Sub
The button calls the various overloaded forms of the CountFiles() function one after the other and prints the results on the TextBox control.
Function overloading is new to VB.NET, but it’s used heavily throughout the language. There are relatively few functions (or methods, for that matter) that aren’t overloaded. Every time you enter the name of a function followed by an opening parenthesis, a list of its arguments appears in the drop-down list with the arguments of the function. If the function is overloaded, you’ll see a
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |