- •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
VARIABLES 107
subtle errors, and they avoid it. It’s up to you to decide whether to use variants and how far you will go with them. Sure, you can perform tricks with variants, but you shouldn’t overuse them to the point that others can’t read your code.
You can also store dates and times in an Object variable. To assign a date or time value to a variant, surround the value with pound signs, as follows:
date1 = #03/06/1999#
All operations that you can perform on date variables (discussed in the section “Date Variables”) you can also perform with variants, which hold date and time values.
Converting Variable Types
In some situations, you will need to convert variables from one type into another. Table 3.3 shows the Visual Basic functions that perform data-type conversions. Actually, you will have to convert between data types quite often now that VB doesn’t do it for you.
Table 3.3: Data-Type Conversion Functions
Function |
Converts Its Argument To |
CBool |
Boolean |
CByte |
Byte |
CChar |
Unicode character |
CDate |
Date |
CDbl |
Double |
CDec |
Decimal |
CInt |
Integer (4-byte integer, Int32) |
CLng |
Long (8-byte integer, Int64) |
CObj |
Object |
CShort |
Short (2-byte integer, Int16) |
CSng |
Single |
CStr |
String |
|
|
To convert the variable initialized as
Dim A As Integer
to a Double, use the function:
Dim B As Double
B = CDbl(A)
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
108 Chapter 3 VISUAL BASIC: THE LANGUAGE
Suppose you have declared two integers, as follows:
Dim A As Integer, B As Integer
A = 23
B = 7
The result of the operation A / B will be a double value. The following statement:
Console.Write(A / B)
displays the value 3.28571428571429. The result is a double, which provides the greatest possible accuracy. If you attempt to assign the result to a variable that hasn’t been declared as Double, and the Strict option is On, then VB.NET will generate an error message. No other data type can accept this value without loss of accuracy.
As a reminder, the Short data type is equivalent to the old Integer type, and the CShort() function converts its argument to an Int16 value. The Integer data type is represented by 4 bytes (32 bits), and to convert a value to Int32 type, use the CInt() function. Finally, the CLng() function converts its argument to an Int64 value.
You can also use the CType() function to convert a variable or expression from one type to another. Let’s say the variable A has been declared as String and holds the value “34.56”. The following statement converts the value of the A variable to a Decimal value and uses it in a calculation:
Dim A As String = “34.56”
Dim B As Double
B = CType(A, Double) / 1.14
The conversion is necessary only if the Strict option is On, but it’s a good practice to perform your conversions explicitly. The following section explains what may happen if your code relies to implicit conversions.
Widening and Narrowing Conversions
In some situations, VB.NET will convert data types automatically, but not always. Let’s say you have declared and initialized two variables, an integer and a double, with the following statements:
Dim count As Integer = 99
Dim pi As Double = 3.1415926535897931
If the Strict option is On and you attempt to assign the value of the pi variable to the count variable, the compiler will generate an error message to the effect that you can’t convert a double to an integer. The exact message is:
Option Strict disallows implicit conversions from Double to Integer
VB6 VB.NET
You will probably see this message many times, especially if you’re a VB6 programmer. In the past, VB would store the value 3 to the count variable and proceed. If you weren’t careful, you’d lose significant decimal digits and might not even know it. This implicit conversion results in loss of accuracy, and VB.NET doesn’t perform it by default. This is a typical example of the pitfalls of turning off the Strict option.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
VARIABLES 109
When the Strict option is On, VB.NET will perform conversions that do not result in loss of accuracy (precision) or magnitude. These conversions are called widening conversions, as opposed to the narrowing conversions. When you assign an Integer value to a Double variable, no accuracy or magnitude is lost. On the other hand, when you assign a double value to an integer variable, then some accuracy is lost (the decimal digits must be truncated). Since you, the programmer, are in control, you may wish to give up the accuracy—presumably, it’s no longer needed. When the Strict option is on, VB.NET doesn’t assume that you’re willing to sacrifice the accuracy, even if this is your intention. Instead, it forces you to convert the data type explicitly with one of the data type conversion functions. Normally, you must convert the Double value to an Integer value and then assign it to an Integer variable:
count = CInt(pi)
This is a narrowing conversion (from a value with greater accuracy or magnitude to a value with smaller accuracy or magnitude), and it’s not performed automatically by VB.NET. Table 3.4 summarizes the widening conversions VB.NET will perform for you automatically.
Table 3.4: VB.NET Widening Conversions
Original Data Type |
Wider Data Type |
Any type |
Object |
Byte |
Short, Integer, Long, Decimal, Single, Double |
Short |
Integer, Long, Decimal, Single, Double |
Integer |
Long, Decimal, Single, Double |
Long |
Decimal, Single, Double |
Decimal |
Single, Double |
Single |
Double |
Double |
none |
Char |
String |
|
|
In the first beta version of Visual Studio .NET, the Strict option was on by default. It seems that pressure from VB6 programmers forced the designers of Visual Studio to change the default setting of this option. I expect that the default settings of the Strict option will be turned on again in the future, and eventually you won’t be able to turn it off.
If the Strict option is off (the default value), the compiler will allow you to assign a Long variable to an Integer variable. Should the Long variable contain a value that exceeds the range of values of the Integer data type, then you’ll end up with a runtime error. Of course, you can avoid the runtime error with the appropriate error-handling code. If the Strict option is on, the compiler will point out all the statements that may cause similar runtime errors, and you can re-evaluate your choice of variable types. You can also turn on the Strict option temporarily to see the compiler’s warnings, then turn it off again.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
110 Chapter 3 VISUAL BASIC: THE LANGUAGE
User-Defined Data Types
In the previous sections, we assumed that applications create variables to store individual values. As a matter of fact, most programs store sets of data of different types. For example, a program for balancing your checkbook must store several pieces of information for each check: the check’s number, amount, date, and so on. All these pieces of information are necessary to process the checks, and ideally, they should be stored together.
A structure for storing multiple values (of the same or different type) is called a record. For example, each check in a checkbook-balancing application is stored in a separate record, as shown in Figure 3.2. When you recall a given check, you need all the information stored in the record.
Figure 3.2
Pictorial representation of a record
To define a record in VB.NET, use the Structure statement, which has the following syntax:
Structure structureName Dim variable1 As varType Dim variable2 As varType
...
Dim variablen As varType End Structure
varType can be any of the data types supported by the framework. The Dim statement can be replaced by the Private or Public access modifiers. For structures, Dim is equivalent to Public.
After this declaration, you have in essence created a new data type that you can use in your application. structureName can be used anywhere you’d use any of the base types (integers, doubles, and so on). You can declare variables of this type and manipulate them as you manipulate all other variables (with a little extra typing). The declaration for the record structure shown in Figure 3.2 is
Structure CheckRecord
Dim CheckNumber As Integer
Dim CheckDate As Date
Dim CheckAmount As Single
Dim CheckPaidTo As String
End Structure
This declaration must appear outside any procedure; you can’t declare a Structure in a subroutine or function. The CheckRecord structure is a new data type for your application. Depending on where the structure was declared, it may not be visible from the entire code, but it’s up to you to give your structure the proper scope (see the section “A Variable’s Scope,” later in this chapter for more information on variable scoping).
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
VARIABLES 111
To declare variables of this new type, use a statement such as this one:
Dim check1 As CheckRecord, check2 As CheckRecord
To assign a value to one of these variables, you must separately assign a value to each one of its components (they are called fields), which can be accessed by combining the name of the variable and the name of a field separated by a period, as follows:
check1.CheckNumber = 275
Actually, as soon as you type the period following the variable’s name, a list of all members to the CheckRecord structure will appear, as shown in Figure 3.3. Notice that the structure supports a few members on its own. You didn’t write any code for the Equals, GetType, and ToString members, but they’re standard members of any Structure object and you can use them in your code. Both the GetType and ToString methods will return a string like “ProjectName.FormName+CheckRecord”.
Figure 3.3
Variables of custom types expose their members as properties.
You can think of the record as an object and its fields as properties. Here are the assignment statements for a check:
check2.CheckNumber = 275 check2.CheckDate = #09/12/2001# check2.CheckAmount = 104.25 check2.CheckPaidTo = “Gas Co.”
You can also create arrays of records with a statement such as the following (arrays are discussed later in this chapter):
Dim Checks(100) As CheckRecord
Each element in this array is a CheckRecord record and holds all the fields of a given check. To access the fields of the third element of the array, use the following notation:
Checks(2).CheckNumber = 275
Checks(2).CheckDate = #09/12/2001#
Checks(2).CheckAmount = 104.25
Checks(2).CheckPaidTo = “Gas Co.”
All data types expose the Equals method, which compares an instance of a data type (a integer variable, for example) to another instance of the same type. This is a trivial operation for simple data
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
112 Chapter 3 VISUAL BASIC: THE LANGUAGE
types, as you can compare the two variables directly. The Equals method can also compare two Structure variables and return True if all of their fields match. If a single field differs, the two objects represented by the variables are not identical. Use this method to compare variables declared as custom structures to avoid comparing all their members. Let’s say you have created two variables of the CheckRecord type:
Dim c1, c2 As CheckRecord
{ assign values to the c1 and c2 variables } If c1.Equals(c2) Then
MsgBox “Same” Else
MsgBox “Different” End If
You can also use arrays as Structure members. The following structure uses an array to store multiple e-mail addresses for the same person:
Structure Person
Dim First As String
Dim Last As String
Dim Address As String
Dim Phone As String
Dim EMail(10) As String
End Structure
Using this structure, you can store up to 10 e-mail addresses per person. To use the Person structure in your code, declare a variable of this type:
Dim aPerson As Person
To access the first element of the EMail member, use the following notation:
aPerson.EMail(0) = “JDoe@tex.com”
You can also declare an array of Person structures, with the following statement:
Dim allPeople(1000) As Person
This array can hold contact information for 1,000 persons, and each person is identified by an index. That is, you must know the index corresponding to each person, or you must search the array to locate the person you’re interested in. In Chapter 11, you’ll learn how to index and search arrays with meaningful keys, like names, rather than indices.
To access an element of the EMail array, use two indices, one for the array of structures and
another one for the array member: allPeople(3).EMail(0), allPeople(3).EMail(1), and so on.
The Nothing Value
The Nothing value is used with Object variables and indicates a variable that has not been initialized. If you want to disassociate an Object variable from the object it represents, set it to Nothing. The following statements create an Object variable that references a Brush, use it, and then release it:
Dim brush As System.Drawing.Brush brush = New System.Drawing.Brush(bmap)
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |