- •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 113
{ use brush object to draw with } brush = Nothing
The first statement declares a Brush variable. At this point, the brush variable is Nothing. The second statement initializes the brush variable with the appropriate constructor. After the execution of the second statement, the brush variable actually represents an object you can draw with. After using it to draw something, you can release it by setting it to Nothing.
VB6 VB.NET
The Set statement is obsolete in VB.NET. You can initialize Object variables just like any other type of variable, with the assignment operator.
If you want to find out whether an object variable has been initialized, use the Is keyword, as shown in the following example:
Dim myPen As Pen
{ more statements here } If myPen Is Nothing Then
myPen = New Pen(Color.Red) End If
The variable myPen is initialized with the New constructor only if it hasn’t been initialized already. If you want to release the myPen variable later in your code, you can set it to Nothing with the assignment operator.
Examining Variable Types
Besides setting the types of variables and the functions for converting between types, Visual Basic provides two methods that let you examine the type of a variable. They are the GetType() and GetTypeCode() methods. The GetType() method returns a string with the variable’s type (“Int32”, “Decimal”, and so on). The GetTypeCode() method returns a value that identifies the variable’s type. The code for the Double data type is 14. The values returned by the GetType() and GetTypeCode() methods for all data types are shown in Table 3.5.
Table 3.5: Variable Types and Type Codes |
|
|
GetType() |
GetTypeCode() |
Description |
Boolean |
3 |
Boolean value |
Byte |
6 |
Byte value (0 to 255) |
Char |
4 |
Character |
DateTime |
16 |
Date/time value |
Decimal |
15 |
Decimal |
Continued on next page
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
114 Chapter 3 VISUAL BASIC: THE LANGUAGE
Table 3.5: Variable Types and Type Codes (continued)
GetType() |
GetTypeCode() |
Description |
Double |
14 |
Double-precision floating-point number |
Int16 |
7 |
2-byte integer (Short) |
Int32 |
9 |
4-byte integer (Integer) |
Int64 |
11 |
8-byte integer (Long) |
Object |
|
Object (a non-value variable) |
SByte |
5 |
Signed byte (–127 to 128) |
Single |
13 |
Single-precision floating-point number |
String |
8 |
String |
UInt16 |
8 |
2-byte unsigned integer |
UInt32 |
10 |
4-byte unsigned integer |
UInt64 |
12 |
8-byte unsigned integer |
|
|
|
Any variable exposes these methods automatically, and you can call them like this:
Dim var As Double
Console.WriteLine(“The variable’s type is “ & var.GetType)
These functions are used mostly in If structures, like the following one:
If var.GetType() Is GetType(System.Double) Then { code to handle a Double value }
End If
Notice that the code doesn’t reference data type names directly. Instead, it uses the value returned by the GetType() function to retrieve the type of the class System.Double and then compares this value to the variable’s type with the Is keyword.
Is It a Number or a String?
Another set of Visual Basic functions returns variables’ data types, but not the exact type. They return a broader type, such as “numeric” for all numeric data types. This is the type you usually need in your code. The following functions are used to validate user input, as well as data stored in files, before you process them.
IsNumeric() Returns True if its argument is a number (Short, Integer, Long, Single, Double, Decimal). Use this function to determine whether a variable holds a numeric value before passing it to a procedure that expects a numeric value or process it as a number. You can also use this function to test a value entered by a user when a numeric value is expected. The following statements keep prompting the user with an InputBox for a numeric value. The user must enter a
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
VARIABLES 115
numeric value, or click the Cancel button to exit. As long as the user enters nonnumeric values, the InputBox pops up and prompts for a numeric value:
Dim strAge as String = “$” Dim Age As Integer
While Not IsNumeric(strAge)
strAge = InputBox(“Please enter your age”) End While
The variable strAge is initialized to a nonnumeric value so that the While…End While loop will be executed at least once. You can use any value in the place of the dollar sign, as long as it’s not a valid numeric value.
IsDate() Returns True if its argument is a valid date (or time). The following expressions return True, because they all represent valid dates:
IsDate(#10/12/2010#)
IsDate(“10/12/2010”)
IsDate(“October 12, 2010”)
If the date expression includes the day name, as in the following expression, the IsDate() function will return False:
IsDate(“Sat. October 12, 2010”) |
‘ FALSE |
IsArray() Returns True if its argument is an array.
IsDBNull() Detects whether an object variable has been initialized or is a DBNull value. This function is equivalent to the IsNull() function of VB6.
IsReference() Returns True if its argument is an object. This function is equivalent to the IsObject() function of VB6.
Tip All these functions are described in the bonus reference “VB.NET Functions and Statements,” on the CD.
Why Declare Variables?
All previous versions of Visual Basic didn’t enforce variable declaration, which was a good thing for the beginner programmer. When you want to slap together a “quick and dirty” program, the last thing you need is someone telling you to decide which variables you’re going to use and to declare them before using them.
But most programmers accustomed to the free format of Visual Basic also carry their habits of quick-and-dirty coding to large projects. When writing large applications, you will probably find that variable declaration is a good thing. It will help you write clean code and simplify debugging. Variable declaration eliminates the source of the most common and pesky bugs.
Let’s examine the side effects of using undeclared variables in your application. To be able to get by without declaring your variables, you must set the Explicit option to Off. Let’s assume you’re using the following statements to convert German marks to U.S. dollars:
DM2USD = 1.562
USDollars = amount * DM2USD
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
116 Chapter 3 VISUAL BASIC: THE LANGUAGE
The first time your code refers to the DM2USD variable name, Visual Basic creates a new variable and then uses it as if it was declared.
Suppose the variable DM2USD appears in many places in your application. If in one of these places you type DM2UDS instead of DM2USD and the program doesn’t enforce variable declaration, the compiler will create a new variable, assign it the value zero, and then use it. Any amount converted with the DM2UDS variable will be zero! If the application enforces variable declaration, the compiler will complain (the DM2UDS variable hasn’t been declared), and you will catch the error.
Many programmers, though, feel restricted by having to declare variables. Others live by it. Depending on your experiences with Visual Basic, you can decide for yourself. For a small application, you don’t have to declare variables; just insert the statement Option Explicit Off at the top of your files. Be warned, though, that the river won’t go backward; VB.NET encourages the explicit declaration of variables, but a future version of VB is quite likely to enforce variable declaration—in the spirit of the other two languages of Visual Studio.
A Variable’s Scope
In addition to its type, a variable also has a scope. The scope (or visibility) of a variable is the section of the application that can see and manipulate the variable. If a variable is declared within a procedure, only the code in the specific procedure has access to that variable. This variable doesn’t exist for the rest of the application. When the variable’s scope is limited to a procedure, it’s called local.
Suppose you’re coding the Click event of a Button to calculate the sum of all even numbers in the range 0 to 100. One possible implementation is shown in Listing 3.5.
Listing 3.5: Summing Even Numbers
Private Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim Sum As Integer
For i = 0 to 100 Step 2
Sum = Sum + i
Next
MsgBox “The sum is “ & Sum
End Sub
The variables i and Sum are local to the Button1_Click() procedure. If you attempt to set the value of the Sum variable from within another procedure, Visual Basic will complain that the variable hasn’t been declared. (Or, if you have turned off the Explicit option, it will create another Sum variable, initialize it to zero, and then use it. But this won’t affect the variable Sum in the Button1_Click() subroutine.) The Sum variable is said to have procedure-level scope. It’s visible within the procedure and invisible outside the procedure.
Sometimes, however, you’ll need to use a variable with a broader scope, such as one whose value is available to all procedures within the same file. In principle, you could declare all variables outside the procedures that use them, but this would lead to problems. Every procedure in the file would have access to the variable, and you would need to be extremely careful not to change the value of a
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
VARIABLES 117
variable without good reason. Variables that are needed by a single procedure (such as loop counters) should be declared in that procedure.
A new type of scope was introduced with VB.NET: the block-level scope. Variables introduced in a block of code, such as an If statement or a loop, are local to the block but invisible outside the block. Let’s revise the previous code segment, so that it calculates the sum of squares. To carry out the calculation, we first compute the square of each value and then sum the squares. The square of each value is stored to a variable that won’t be used outside the loop, so we can define the sqrValue variable in the loop’s block and make it local to this specific loop, as shown in Listing 3.6.
Listing 3.6: A Variable Scoped in Its Own Block
Private Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Button1.Click Dim i, Sum As Integer
For i = 0 to 100 Step 2 Dim sqrValue As Integer sqrValue = i * i
Sum = Sum + sqrValue Next
MsgBox “The sum of the squares is “ & Sum End Sub
The sqrValue variable is not visible outside the block of the For…Next loop. If you attempt to use it before the For statement, or after the Next statement, VB will throw an exception. Insert the statement
Console.WriteLine(sqrValue)
after the call to the MsgBox function to see what will happen: the sqrValue variable maintains its value between iterations. If you insert the WriteLine statement after the line that declares the variable, you will see that it’s not initialized at each iteration, even though there’s a Dim statement in the loop.
The values printed by this statement will keep getting larger, and they’re not reset to zero. Of course, if you re-enter the block in which a variable is declared, you must initialize the variable to avoid side effects. Even though the variable’s scope is the block in which it was declared, it exists while the subroutine is executing.
Another type of scope is the module-level scope. Variables declared outside any procedure in a module are visible from within all procedures in the same module, but they’re invisible outside the module. Variables with a module-level scope can be set from within any procedure, so you should try to minimize the number of such variables. Setting many variables from within many procedures can seriously complicate the debugging of the application. Beginners have a tendency to overuse module-level scope, because they simplify the exchange of data among procedures. You can write procedures that don’t accept any arguments—they simply act on module-level variables. Even though they may simplify small projects, too many variables with module-level scope reduce the maintainability and readability of large projects.
Let’s say you’re writing a text-editing application that provides the usual Save and Save As commands. The Save As command prompts the user for the filename in which the text will be stored.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
118 Chapter 3 VISUAL BASIC: THE LANGUAGE
The Save command, however, must remember the name of the file used with the most recent Save As command, so that it can save the text to the same file. It must also remember the name of the file that was read most recently, so that it can save the text back to the same file. The path of the file is needed from within three separate procedures, so it must be saved in a variable with module-level scope: the Open procedure should be able to set this variable, the Save As procedure should be able to either read or set it, and the Save procedure should be able to read it. This is a typical example of a variable with module-level scope.
Finally, in some situations the entire application must access a certain variable. In this case, the variable must be declared as Public. Public variables have a global scope: they are visible from any part of the application. To declare a public variable, use the Public statement in place of the Dim statement. Moreover, you can’t declare public variables in a procedure. If you have multiple forms in your application and you want the code in one form to see a certain variable in another form, you can use the Public modifier. You can also make a control on a form visible outside its own form, by setting its Modifier property to Public. Setting this property causes VB to insert the Public keyword in the declaration of the control.
Note You will learn how to access variables declared in one form from within another form’s code, in Chapter 5.
The Public keyword makes the variable available not only to the entire project, but also to all projects that reference the current project. If you want your variables to be public within a project (in other words, available to all procedures in any module in the project) but invisible to referencing projects, use the Friend keyword in the declaration of the module. Variables that you want to use throughout your project, but not have available to other projects that reference the current one, should be declared as Friend. There is no way to make some of the public variables available to the referencing projects.
So, why do we need so many different types of scope? You’ll develop a better understanding of scope and which type of scope to use for each variable as you get involved in larger projects. In general, you should try to limit the scope of your variables as much as possible. If all variables were declared within procedures, then you could use the same name for storing a temporary value in each procedure and be sure that one procedure’s variables don’t interfere with those of another procedure, even if you use the same name. Not that you can run out of variable names, but names like tempString, amount, total, and so on are quite common. All loop counters should also be local to the procedure that uses them. The variable counter in the following loop should never be declared outside the procedure:
For counter = 1 To 100 { statements }
Next
This statement repeats the block of statements 100 times. There’s absolutely no reason to declare the counter variable outside the procedure. Most programmers tend to use the same counter names in all of their loops, so they have to use local variables.
Procedure-level variables are necessary, but you should try to minimize their use. If a variable looks like a good candidate for procedure-level scope, see if you can implement the code with two or more local-level scope variables. Many procedure-level variables can be reduced to local-level variables if
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
