Chapter 2. Introducing Visual Basic

It was a dark and stormy night. Hector gazed wearily through his bloodshot eyes, through the black-rimmed corrective lenses, and through the haze of the fluorescent overhead lights at the phosphor-enriched display. Had it really been four months since he started the six-month project? Did his boss really threaten to fire him after seeing his progress? It seemed like all of those MS-DOS programs he had written for the company over the years meant nothing. Why did he promise to port the company’s main internal system to Windows? In a moment of despair, tears streamed down his cheeks, diluting his last remaining can of Jolt Cola.

It’s 8:00 a.m. A loud thump on Hector’s desk brings him suddenly out of his slumber, the drool still trickling from the corner of his mouth. What’s that? What’s that box on his desk? “V-i-s-u-a-l B-a-s-i-c?” A note on the box says to rewrite his code in “this.” Desperate to try anything, Hector installs the three floppy disks on his ’386 powerhouse.

Six weeks later, Hector has completed the project, ahead of schedule, feature-complete, and with the accolades of his boss and department. And it’s all due to Visual Basic. But VB didn’t just improve his programming life. Overall, he’s happier, has kicked the caffeine habit, is able to bench-press 300 pounds, no longer walks with a limp, has increased libido, and has whiter teeth. “Thank you, Visual Basic 1.0!”

The History of the Visual Basic Revolution

It’s possible that I got a few of the details wrong in Hector’s life. But for many business developers, Visual Basic 1.0 was a breath of fresh air. It’s not that they could do more with Visual Basic; programs written in C were more powerful and had greater flexibility. But business programmers didn’t always need that flexibility back in the transition from MS-DOS. They just wanted to manage data, and they didn’t want to worry about how to present every little pixel on the screen. Visual Basic provided the tools to write applications quickly and with much less effort than that required by other Windows development tools and languages.

Visual Basic’s simplicity was embraced by developers everywhere, but the honeymoon quickly wore off. Given the speed at which programs of reasonable quality could be cranked out with Visual Basic, programmers and businesses began demanding more. And Microsoft responded. Visual Basic 2.0 and 3.0 were released in quick succession in 1992 and 1993, providing enhanced database integration and additional visual development features. Version 4.0, released in 1996, introduced 32-bit programming to the language, and support for the already-popular Windows 95 platform. Two more quick releases—Visual Basic 5.0 in 1997 and Visual Basic 6.0 in 1998—added even more features and complexity to the otherwise “basic” language, features supporting some but not all object-oriented programming (OOP) techniques, ActiveX control development, and web-based logic coding. Microsoft had even integrated the core Visual Basic engine—christened Visual Basic for Applications, or VBA—into its suite of Office products, proclaiming it as the new official macro language and making the engine available to any third party that wanted to do the same.

Seven years after its initial introduction, Visual Basic had taken the programming world by storm. Millions of developers were using the language, including in-house developers at Fortune 500 companies, writing applications that supported core business functions. VB still retained some of the flavor of the original BASIC language—a “beginner’s” programming language developed by John Kemeny and Thomas Kurtz at Dartmouth College back in 1963. This caused no end of snickering from C and C++ developers and other cola addicts. But VB programmers could see a powerful future for their language of choice.

Then the unthinkable happened. Microsoft announced that it would no longer enhance the core Visual Basic engine. Instead, it would rewrite and reimplement Visual Basic using its soon-to-be-released .NET development platform. Yes, Visual Basic would be endowed with all the power promised for Microsoft’s new C- and Java-like language, C#. But for many hardcore VB developers, it was wrong, just wrong. Words were exchanged. Petitions were crafted. Letters to the editor sounded the call to the Visual Basic faithful, urging them to never write a single line of Visual Basic .NET code, ever. In frustration, a Visual Basic user’s group set fire to the entire Microsoft campus in Redmond.

Well, that didn’t happen. In fact, nothing bad happened at all. Visual Basic .NET turned out to be a software wunderkind, providing power and features that far surpassed anything available in Visual Basic 6.0. Its initial release in 2002 was proof that. Visual Basic .NET 2002 was powerful, but it was also a little hard to use, at least compared with version 6.0, and especially when compared with the original 1.0 product. Visual Basic .NET 2003, released just a year later (obviously), was a relatively minor update with not much in the way of new or easier functionality.

Visual Basic 2005 marked a return to the simpler days of Visual Basic development, days of harmony and peace between “newbies” and their general-purpose programming language. Not only did Microsoft remove the term “.NET” from the product name, but it also removed some of the barriers that kept entry-level programmers from approaching the language. Pre-.NET features, such as Edit and Continue and the display of forms through the simple use of the form’s name, once again found their way into the language and into the hearts of software engineers. Visual Basic still retained all the power it gained with .NET, but with true improvements in usability. It was like when they add a label to your toothpaste that says, “New package, same great regular flavor!” Except that Visual Basic’s flavor was improved, too. Visual Basic was once again accessible to first-time developers.

Since the 2005 release, Microsoft hasn’t just been sitting on its laurels, as painful as that would be. It dug into its bag of tricks with both hands and came out with Visual Basic 2008, the latest VB offering. Formerly code-named Orcas, Visual Basic 2008 brings additional power and simplicity—yes, both of those—to the language. The biggest new feature, LINQ, makes data access easier by letting you tell the system what data you want instead of detailing how to obtain that data. The language also provides more direct access to new technologies such as Ajax and the Windows Presentation Foundation (WPF). But enough fawning. Let’s start learning about the language.

Visual Basic from the Inside Out

As a general-purpose development language, Visual Basic includes gobs of features that allow you to develop just about any type of application supported by the Microsoft Windows platform. As such, all of its features could never be covered in a concise, 20- or 30-page chapter, and I won’t try. What I will do in this chapter is to introduce you to the basics of the language, and its core features. Features not covered in this chapter are discussed throughout the rest of the book. It has to be that way, since I don’t want you to finish this chapter and then say to yourself, “That Tim Patrick is so amazing. I learned all I needed to know about Visual Basic in one chapter; I didn’t even have to read the rest of the book.” My publisher would not be amused.

In the remainder of this chapter, I will take the “from the inside out” approach, starting the discussion with the core concepts of logic and data, and adding layer after layer of Visual Basic functionality as you turn the pages.

The Basics of Logic and Data

Lest you forget it, let me remind you again: computers are not really very smart. They know how to do only the simplest of tasks. If you want them to do anything remotely complex, you have to give precise, step-by-step instructions down to moving individual bits of data—only 1s and 0s, remember—around in memory. Fortunately, most of the code you would ever need at that low level has already been written for you, and incorporated into the Windows operating system and the .NET Framework. Microsoft- and third-party-supplied code libraries give you a lot of prewritten functionality that’s available for use in your own programs. And that’s good, because you would rather be hurtled into space on a giant bungee cord than have to write business applications at the machine code level all day long.

Even though you have all this great prewritten code in your arsenal, you still have to tell the computer precisely what you want it to do, in fine detail, or it won’t do it. And that’s where high-level languages like Visual Basic come in. They provide the grammar you need to communicate with the computer. For any given tasks that the computer needs to perform, your job as a programmer is to determine the individual steps to accomplish that task—the logic—and translate those steps into computer-ese using the programming language.

As an example, let’s say you receive a request from the sales department for a program that will reverse all the letters in any chunk of text provided to the program. “Our customers are clamoring for this; we need it by Tuesday,” they say. OK, so first you figure out the logic, and then you implement it in Visual Basic. Using pseudocode, an artificial programming language that you make up yourself to help you write programs, you can sketch out the basics of this task (with leading line numbers):

01  Obtain the original text (or string) from the user.
02  If the user didn't supply any content, then quit now.
03  Prepare a destination for the reversed string, empty for now.
04  Repeat the following until the original string is empty:
05     Copy the last character from the remaining original string.
06     Put that character onto the end of the destination string.
07     Shorten the original string, dropping the last character.
08  [End of repeat section]
09  Show the user the destination string.

You could write this logic in many ways; this is just one example. You can now convert this pseudocode into your language of choice; in this case, Visual Basic (don’t worry about the syntax details for now):

01  originalText = InputBox("Enter text to reverse.")
02  If (Len(originalText) = 0) Then Return
03  finalText = ""
04  Do While (originalText <> "")
05     oneCharacter = Right(originalText, 1)
06     finalText &= oneCharacter
07     originalText = Left(originalText, _
          Len(originalText) - 1)
08  Loop
09  MsgBox("The reverse is: " & finalText)

This source code is now ready to be used in a Visual Basic program. And it also demonstrates several essential aspects of coding:

  • The individual steps of the step-by-step instructions are called statements. In Visual Basic, each statement appears on a line by itself. You can break long statements into multiple lines by connecting the lines with a space-underscore pair, as shown in line 07 of the code. When a single statement is spread across multiple lines in this manner, the entire statement is sometimes called a logical line. Since a single logical line often includes only a single primary Visual Basic action (such as the If or Do action, or the various assignment actions using the equals sign [=]), these actions are also referred to as statements.

  • The statements of the code are processed one at a time, from top to bottom. However, certain statements alter the normal top-to-bottom flow of the program, as is done with the Do While...Loop block on lines 04 and 08 of the sample code. Such statements are called flow control statements, and include loops (repeating a block of code), conditions (optionally processing a block of code based on a comparison or calculated result), and jumps (moving immediately to some other section of the code).

  • Data can be stored in variables, which are named containers for data values. The sample code block includes three variables: originalText, oneCharacter, and finalText, all of which store text (string) data. The .NET Common Type System (CTS) allows you to create variables for four primary types of basic data values: text (both single characters and longer strings), numbers (both integer and decimal values), dates (and times), and Booleans (true or false values). You can also build more complex types of data by grouping the basic types.

  • Data is stored in a variable through an assignment. Generally, this involves placing a variable name on the left side of an = assignment operator, and putting the data or calculation to store in that variable on the right side of that same equals sign. The statement finalText = "" on line 03 stores an empty string ("") in the variable finalText. The &= assignment statement on line 06 shows a slightly different assignment syntax.

  • Statements can include function calls, blocks of prewritten functionality, all squished down into a single name. Function calls do a bunch of work, and then return a final result, a data value. Function names are followed by a set of parentheses, which may include zero or more arguments, additional data values supplied by the calling code that the function uses to generate its result.

    The sample code includes many examples of function calls, including the Right function on line 05. This function returns a copy of the rightmost characters from another text string. It accepts two parameters: the original string from which to extract the rightmost characters, and an integer value indicating the number of characters to return. The code Right(originalText, 1) returns a copy of the rightmost single character (1) from originalText.

    When you use a function in your source code, the function acts a little like a variable; all the text of the function call, from the start of its name to the end of its closing parenthesis, could be replaced by a variable that contained the same resulting data. Function calls cannot appear on the lefthand side of an assignment statement, but they can appear almost anywhere else that a variable can appear. For example, the following two lines could be used to replace line 02 in the sample:

    ' Replacing --> If (Len(originalText) = 0) Then Return
    lengthOfText = Len(originalText)
    If (lengthOfText = 0) Then Return
  • In addition to functions, Visual Basic also includes procedures. Procedures bundle up prewritten code in a named package, just like functions, but they don’t return a value. They must be used as standalone statements; you cannot use them where you would use a variable or a function call. The call to MsgBox on line 09 is a typical example of a procedure call in use. (MsgBox is actually a function, but in this code it is masquerading as a procedure; more on that later.)

The sample code listed previously could be made a little more efficient. In fact, it’s entirely possible that Microsoft obtained an early draft of this book, since it included a string-reversal feature right in Visual Basic, and called it StrReverse:

originalText = InputBox("Enter text to reverse.")
If (Len(originalText) = 0) Then Return
finalText = StrReverse(originalText)
MsgBox("The reverse is: " & finalText)

That’s right; Visual Basic already includes a string-reversal feature, some of that prewritten library code I keep talking about. Visual Basic includes many such intrinsic functions that are considered part of the language, and that bundle up useful prewritten functionality. Many of these functions appear in the Microsoft.VisualBasic namespace, which is automatically made available to your Visual Basic source code when you create a new VB project.

Data Types and Variables

Take my data . . . please! Ha, ha, that one always cracks me up. But it’s actually what I ask my Visual Basic application to do: take data from some source (keyboard, hard disk, Internet, etc.) and present it in some useful way. All programs I write will actively manage at least some data in memory. Each data value is stored in a specific area of the computer’s memory, as determined by the Common Language Runtime (CLR). The statements in Visual Basic exist primarily to manage and manipulate this data in useful and complex ways.

All data managed by the CLR is stored in the computer’s memory, with each data value separated and protected from all others. It’s as though each data value had its own individual teacup, as in Figure 2-1.

All types of teacups and data

Figure 2-1. All types of teacups and data

All data values managed by the CLR have content and type. Content is the actual data: the text string “abc,” the number 5, a sales invoice, orange pekoe. Whatever you put in the teacup, that’s the content. In some cases, .NET allows you to store absolutely nothing in the teacup (for reference types as described shortly, or “nullable” value types as described in Chapter 6).

Type indicates the kind of content stored in the teacup. In Figure 2-1, this is shown by the shape of each teacup. Each teacup has limits on the type of data that can be poured into the teacup: a text string, an integer number, a customer invoice.

Literals

Some basic data values, such as numbers and text strings, can be entered into your source code and used just as they are. For instance, the MsgBox procedure displays a window with a supplied text message. The statement:

MsgBox("The answer is " & 42)

includes a literal string, “The answer is,” and a literal integer value, 42. (The “&” symbol is an operator that connects two values together into a new string.) Literals are used once, and then they’re gone. If I wanted to show the same “The answer is 42” message again, I would have to once again type the same literal values into a different part of the source code.

Visual Basic supports several types of basic literals. String literals are always surrounded by quote marks. If you want to include a quote mark itself in the middle of a string, include two instead of one:

"This is ""literally"" an example."

String literals can be really, really long, up to about 2 billion characters in length; if you were to type just one character per second, it would take more than 63 years to reach the maximum string length. Visual Basic also includes a character literal that is exactly one character in length; if you were to type just one character per second, well, never mind. These character literals are recognized by the “c” trailing after the string. The character literal “A” is entered as:

"A"c

Date and time literals are surrounded by number signs instead of quote marks. The date or time (or both) that you include can be in any format recognized by Microsoft Windows in your specific region. If you are using Visual Studio, it will reformat your date when you type in the literal:

#7/4/1776#

Eleven different kinds of numeric data values—both integers and floating-point values—make up the “core” set of numeric teacups. And who needs more than 11? With these 11 teacups, you can manage numbers from zero all the way to 1 × 10300 and beyond. To use a numeric literal, type the number right in your code, like 27, or 3.1415926535. Visual Basic also lets you specify which of the 11 numeric teacups to use for a number, by appending a special character to the end of the number. Normally, 27 is an integer 27. To make it a currency-focused “decimal,” append an at sign (@):

27@

When I talk about data types in full detail in Chapter 6, I will list the different special characters, like @, that set the data type for literal numbers.

The fourth and final type of Visual Basic literal is the Boolean literal. Boolean values represent the simplest type of computer data: the bit. Boolean values are either true or false, on or off, yes or no, delicious or disgusting, cats or dogs, zero or nonzero. Booleans always represent any two opposite values or states. Back in the 1800s, George Boole invented Boolean algebra, a language he used to represent logic statements as mathematical equations. It just so happens that computers love Boolean algebra. All the basic operations of a computer, such as addition, are implemented using Boolean functionality.

Visual Basic includes the Boolean literals True and False. No quotes; no number signs—just the words True and False. Question: is Tim Patrick telling the truth about this? Answer:

True

In certain cases, you can treat numbers as Boolean values. I’ll talk about it more later on, but for now just know that False equates to zero (0), and True equates to everything else (although generally, −1 is used for “everything else”).

Variables

Literal data values are all well and good, but they are useful only once, and then they’re gone. Each time you want to use a literal value, you must retype it. It’s as though the data values are stored in disposable cups instead of fine china teacups. And besides, only programmers enter literal values, not users, so they are of limited use in managing user data.

Variables are not simply disposable cups; they are reusable. You can keep putting the same type of tea over and over into the teacup. A string variable teacup can hold a string for reuse over and over. For instance, in this block of code, response holds the various strings assigned to it:

01  response = "A"
02  MsgBox("Give me an 'A'!")
03  MsgBox(response)
04  MsgBox("Give me another 'A'!")
05  MsgBox(response)
06  MsgBox("What's that spell?")
07  response = StrDup(2, "A")
08  MsgBox(response)

The variable response is assigned twice with two different strings: an “A” (line 01) and then “AA” (line 07). It keeps whatever value was last assigned to it; both lines 03 and 05 display “A” in a message box window. And you don’t have to assign just literal strings to it; anything that generates a string can assign its result to response. Line 07 uses a built-in Visual Basic function, StrDup, to return the two-character string “AA” and assign it to response.

Using variables is a two-step process. First you must declare the variable, and then you assign a value to it. The Dim statement takes care of the declaration part; it lets you indicate both the name and the type of a variable. Its basic syntax is pretty straightforward:

Dim response As String

where response is the name of the variable and String is its type. Assignment occurs using the = assignment operator:

response = "The answer"

A single variable can have new values assigned to it over and over again. For those times when you want your variable to have some specific value immediately upon declaration, you can combine declaration and assignment into a single statement:

Dim response As String = "The answer"

Of course, you’re not limited to just a single declaration; you can create as many variables as you need in your code. Each one normally uses its own Dim statement:

Dim question As String
Dim answer As String

You also can combine these into a single statement, although I think it’s just plain ugly:

Dim question As String, answer As String

See, I told you it was ugly. This is just the start of what’s possible with the Dim statement. I’ll get into more details as the chapter progresses.

Value Types and Reference Types

I talked about value types and reference types in Chapter 1. Value type variables store an actual value; the tea in a value type teacup is the content itself. All of the literal data values I mentioned previously, except for Strings, are value types.

Reference type variables store a “reference” to the actual data, data found somewhere else in memory. When you look into a reference type teacup, you have to read the tea leaves at the bottom to determine where the real data resides.

Either reference types have data or they don’t. In the absence of data, a reference type has a value of Nothing, a Visual Basic keyword that indicates no data. Value types are never Nothing; they always contain some value, possibly the default value for that type (such as zero for numeric types). A special “nullable” type does let you assign Nothing to a value type, allowing you to implement the same “is there any data here at all” logic that exists with reference types. I’ll talk about nullable types in Chapter 6.

Data Types

The String data type is useful, but it’s only one of the teacup shapes at your disposal. The .NET Framework defines several core data types. Each data type is implemented as a specific class within the System namespace. The most basic data type, a large teacup that can hold any type of data, is called Object. More than just an object, this is object with a capital O. In the .NET Class Library namespace hierarchy, it’s located at System.Object. It’s the mother of all classes in .NET; all other classes, structures, enumerations, and delegates, no matter where they reside in the namespace hierarchy, whether they are written by Microsoft or by you, derive from System.Object. There’s no getting around it; you cannot create a type that ultimately derives from anything else.

So, back to these “core” data types I’ve been hinting at. They match the four types of literal data values I listed before: strings, dates, numbers, and Boolean values. Table 2-1 lists these core data types. Each type also has a Visual Basic-specific name that you can (and should) use instead.

Table 2-1. Core .NET and Visual Basic data types

VB name

.NET name

Description

[a]

Boolean

Boolean

The Boolean data type supports only values of True and False. It’s possible to convert numbers to Boolean values: 0 becomes False and everything else becomes True. When you convert a Boolean back to a number, False becomes 0 and True becomes −1.[a]

Byte

Byte

A numeric data type, Byte stores single-byte (8-bit) unsigned integers, ranging from 0 to 255. The Byte data type is pretty useful for working with nontext data, such as graphical images.

Char

Char

The Char data type holds exactly one text character. Each Char data value represents two bytes (16 bits) of storage, so it can manage double-byte character sets, providing support for languages such as Japanese that have a large number of characters. Although it is used to store single text characters, internally the Char data type maintains the characters as integer values, ranging from 0 to 65,535.

Date

DateTime

This date and time data type handles all dates between January 1, 1 AD and December 31, 9999 AD, in the Gregorian calendar. The time can be included as well; if no time is specified, midnight is used. Internally, the Date data type stores the date and time as the number of “ticks” since midnight on January 1, 1 AD. Each tick is 100 nanoseconds.

Decimal

Decimal

The Decimal data type is designed with currency in mind. It is very accurate in mathematical calculations, and has a pretty good range, supporting numbers just beyond 79-octillion, positive or negative. (Did he say 79-octillion?) That’s 29 digits long, and that’s important to remember, since you get only 29 digits total on both sides of the decimal point. That 79-octillion number comes with the limitation of no digits to the right of the decimal point. If you want one decimal position, you have to give up one to the left (the mantissa) and only keep numbers up to 7.9-octillion. If you want 29 digits after the decimal, you get a big fat zero for the mantissa. If you used to use Visual Basic 6.0, Decimal is similar to the Currency sub-data type.

Double

Double

The Double data type handles the largest possible numbers of all the core numeric data types. Its range is about 4.94 × 10−324 to 1.798 × 10+308 for positive numbers, with a similar range for negative values. While you may think you are in giganto-number heaven, it’s not all harps and wings. The Double data type is notoriously inaccurate in complex calculations. Sometimes a calculation that should result in zero will actually calculate as something like 0.00000000000005434, which is close. But comparisons of this number with zero will fail, since it is not zero.

Integer

Int32

The Integer data type is a 4-byte (32-bit) signed integer type. It handles numbers from −2,147,483,648 to 2,147,483,647. If you are a pre-.NET Visual Basic programmer, this new Integer data type is equivalent to the version 6.0 Long data type.

Long

Int64

The Long data type is even bigger than Integer; it’s an 8-byte (64-bit) signed integer type. It handles numbers from −9,223,372,036,854,775,808 (wow!) to 9,223,372,036,854,775,807 (wow! wow!). It is not the same as the old Visual Basic 6.0 Long data type, as it has twice the storage capacity.

Object

Object

Object is the core type for all .NET types. It sits at the top of the class and type hierarchy; it is the ultimate base class for all other classes. It is a reference type, although value types eventually derive from it, too.

SByte

SByte

A numeric data type, SByte stores single-byte (8-bit) signed integers, ranging from −128 to 127. It is the signed version of the unsigned Byte data type.

Short

Int16

The Short data type is a 2-byte (16-bit) signed integer type. It stores numbers from −32,768 to 32,767. If you are a pre-.NET Visual Basic programmer, this new Short data type is equivalent to the version 6.0 Integer data type.

Single

Single

The Single data type is pretty much like the Double data type, only smaller. Its range for positive numbers is about 1.4 × 10−45 to 3.4 × 10+38, with a similar range for negative numbers. Like the Double data type, the Single data type suffers from slight inaccuracies during calculations.

String

String

The String data type is a reference type that stores up to about 2 billion characters of text. It stores Unicode characters, which are 2-byte (16-bit) characters capable of storing characters from most languages in the world, including languages with large alphabets, such as Chinese.

UInteger

UInt32

UInteger stores 4-byte (32-bit) unsigned integers, ranging from 0 to 4,294,967,295. It is the unsigned version of the signed Integer data type.

ULong

UInt64

ULong stores 8-byte (64-bit) unsigned integers, ranging from 0 to 18,446,744,073,709,551,615. It is the unsigned version of the signed Long data type.

UShort

UInt16

UShort stores 2-byte (16-bit) unsigned integers, ranging from 0 to 65,535. It is the unsigned version of the signed Short data type.

[a] This is true only in Visual Basic. In other .NET languages, such as C#, False becomes 0, but True becomes 1, not −1. If you keep a Boolean value as Boolean, it is normally not an issue. But if you first convert your Booleans to numbers, and then start passing them around willy-nilly between code from different .NET languages, you may get surprising results.

The Microsoft developers in charge of Visual Basic data types lucked out on that job since all core Visual Basic data types are simply wrappers for specific data types implemented by .NET. The Visual Basic names given for each of these core data types are fully interchangeable with the .NET names. For example, Integer is fully equivalent to System.Int32. In fact, when writing Visual Basic code, it is better to use the Visual Basic synonyms, since most Visual Basic developers expect these data type names in the code they read and write.

Except for Object and String, all of these data types are value types. All value types are derived from System.ValueType (which in turn derives from System.Object).

The SByte, UInteger, ULong, and UShort data types were added to Visual Basic with its 2005 release, although their System namespace equivalents have been in .NET since its inception. Unlike the other core data types, these four types are not “CLS-compliant”; that is, they cannot be used to interact with .NET components and languages that limit themselves to just the very core required features of .NET. Generally this is not much of a limitation, but be on your guard when working with third-party components or languages.

Advanced Declaration

When I mentioned the need for declaration and assignment of variables, I was really focusing on value types. Reference types require one additional step: instantiation. Consider the following declaration statements:

Dim defaultValue As Integer
Dim nonDefaultValue As Integer = 5
Dim defaultReference As Object

These lines declare three separate variables: two value types (the Integers) and one reference type (the Object). Although only one variable has an explicit data assignment, all three have actually been assigned something, either explicitly or implicitly. Let’s look at those statements again and see what is truly being assigned to each variable.

Dim defaultValue As Integer = 0
Dim nonDefaultValue As Integer = 5
Dim defaultReference As Object = Nothing

Both declaration and assignment already occurred for all the variables, just by using the Dim statement. The defaultValue variable, with its default assignment of 0, can be used immediately in equations. However, the reference type variable defaultReference is just an empty teacup, with no default data to manipulate. There are features in Visual Basic that let you compare a reference type with Nothing, and you could do this immediately, but it’s not really data. And remember, variables live to manage data.

Reference data values need instantiation, and instantiation needs the New keyword:

Dim defaultReference As Object = New Object

Now defaultReference points to a real object; now the defaultReference teacup has something consumable inside it, although since it is just System.Object, it doesn’t have much in the way of flavor. Strings are a little more interesting, and they also have more interesting constructors.

As you may recall from way back in Chapter 1, a constructor is a block of initialization code that runs when you create a new data value or object. Some objects allow you to supply extra information to a constructor, additional information that is used in the initialization process. A default constructor doesn’t allow you to supply any extra information; it just works on its own, initializing data like it was nobody’s business. There is no limit on the number of constructors in a class, but each one must vary in the type of extra information passed to it.

So, back to Strings. The default constructor for a string simply creates a blank, zero-length string:

Dim worldsMostBoringString As String = New String

Now, nobody ever does this, since the following statement works just as well:

Dim worldsMostBoringString As String = ""

That’s because Strings are treated specially by Visual Basic. String literals are actually instantiations of String data values; it’s as though you created a new String instance using the System.String class. At least that’s true when using the String data type’s default constructor. But String also has more interesting constructors. (I’ll delve into the details of constructors in Chapter 8.) One of the constructors creates a new String instance initialized with a specific character repeated a number of times. For instance, to create a String instance with a 25-character string of the letter M, use the following syntax:

Dim mmGood As String = New String("M"c, 25)

If you’re going to use the same data type just after the As keyword that you use right after the New keyword, you can use a collapsed syntax:

Dim mmGood As New String("M"c, 25)

As with value types, you can also break the statement into distinct declaration and assignment statements:

Dim mmGood As String
mmGood = New String("M"c, 25)

Constants

Literals don’t change, but you can use them only once in your code. Constants are a cross between a literal and a variable; they have a single, never-changing value just like data literals, but they also have a name that you can use over and over again, just like variables.

You declare constants using the Const keyword instead of the Dim keyword:

Const SpeedOfLight As Integer = 186000

Actual assignment of the value to the constant occurs in the statement itself, with the value following the = operator. Once your constant is declared and assigned, it’s available for use in actual statements of your actual code:

MsgBox("Lightspeed in miles/second: " & SpeedOfLight)

Local Declaration and Fields

In the real world, you need to keep some data private, for your use only. Your neighbors have other juicy bits of data and information that they share among themselves. And then there is public data that isn’t hidden from anyone. But it’s not just this way in the real world; the fake world of Visual Basic has different levels of access and privacy for your data.

A little later in the chapter, we’ll see that your application’s logic code will always appear in procedures, named blocks of source code. You declare local variables (and constants) in these same procedures when you need a short-lived and personal variable that is only for use within a single procedure. Other variables (and constants) can appear outside procedures, but still within the context of a class or similar type. These fields, whether variable or constant, are immediately available to all the different procedures that also call the current class home.

You define all local variables using the Dim keyword. The Dim statement works for field definitions, but it’s more common to use special access modifier keywords instead. These modifiers determine what code can access the fields, from Private (used only by code inside the class) to Public (also available outside the class):

Private ForInClassUseOnly As Integer

There are five access modifiers in all. I’ll talk more about them and about fields in general in Chapter 6.

Intermission

That was a lot to take in. Getting your mind around data and variables is probably the most complex part of programming in Visual Basic. Once you have the data in variables, it’s pretty easy to manipulate.

Although the thought of a cup of tea may cause you to run out of the room like a raving lunatic, you might want to take a few minutes, grab a cup, glass, saucer, or mug of your beverage of choice, and relax. I’ll see you in about 20 or 30 minutes.

Comments

If you’re an opera fan, you know how exciting a good opera can be, especially a classic work presented with the original foreign language libretto. If you’re not an opera fan, you know how irritating it can be to listen to several hours of a foreign language libretto. With the advent of “supra titles” conveying the English-language interpretation of the content, those who until now have gotten little joy out of the opera experience will still find it repulsive, only this time in their native tongue. But at least now they will know why they don’t enjoy the story.

That’s really what comments do: tell you in your own language what is actually going on in a foreign language. In this book, the foreign language is Visual Basic, and English is the vernacular. You may find a particular block of Visual Basic code to be poorly written or even detestable, but if the accompanying comments are accurate, you can be disgusted in your own language, with a human-language understanding of the process.

Comments normally appear on lines by themselves, but you may also attach a comment to the end of an existing code line. If a logical line is broken into multiple physical lines using the “_” line continuation character, a trailing comment is valid only at the end of the final physical line:

' ----- This is a standalone comment, on a line by itself.
Dim counter As Integer   ' This is a trailing comment.
MsgBox("The counter starts at " & _   ' INVALID COMMENT HERE!
   counter)  ' But this one is valid.

Comments begin with the comment character, the standard single quote character ('). Any text following the comment character is a comment, and is ignored when your code is compiled into a usable application. Any single quote that appears within a literal string is not used as a comment marker.

MsgBox("No 'comments' in this text.")

Comments can also begin with the REM keyword (as in “REMark”), but most programmers use the single-quote variation instead.

Option Statements

A few code examples ago you saw that Visual Basic would supply a default assignment to a variable—at least for value types—if you neglected to include one. In certain cases, Visual Basic will also supply the declaration if you leave it out. In the statement:

brandNewValue = 5

if there is no related Dim statement that defines brandNewValue, Visual Basic will declare the variable on your behalf, assigning it to the Object data type. Don’t let this happen to you! You don’t know what kind of trouble you will have if you allow such practices in your code. You will quickly find your code filled with mysterious logic bugs, esoteric data issues, recurrent head lice, and so on.

The problem is that Visual Basic will not complain if you mistype the name of your auto-declared variable. Left unchecked, such practices could lead to code such as this:

brandNewValue = 5
MsgBox(brandNewVlaue)

My, my, my, look at that spelling mistake on the second line. What? Visual Basic compiled without any error? And now your message box displays nothing instead of 5? You could avoid such trauma by judicious use of the Option statements included in the Visual Basic language. There are four such statements:

Option Explicit On

This statement forces you to declare all variables using Dim (or a similar statement) before use. It’s possible to replace “On” with “Off” in the statement, but don’t do it.

Option Strict On

Visual Basic will do some simple data conversions for you when needed. For instance, if you assign a 64-bit Long data value to a 32-bit Integer variable, Visual Basic will normally convert this data to the smaller size for you, complaining only if the data doesn’t fit. This type of conversion—a narrowing conversion—is not always safe since the source data will sometimes fail to fit in the destination. (A widening conversion, as with storing Integer data in a Long, always works, since the destination can always hold the source value.) The Option Strict On statement turns off the automatic processing of narrowing conversions. You will be forced to use explicit conversion functions to perform narrowing conversions. This is good, since it forces you to think about the type of data your variables will hold. You can replace “On” with “Off” in this statement, but if I’ve warned you once, I’ve warned you twice: don’t even try it.

Option Infer On

This new Visual Basic 2008 statement tells the compiler to make a guess at which data type you want a variable to use when you don’t specifically tell it. I discuss type inference in Chapter 6, so I’ll delay the details for now. Usually you will want to keep this option set to “On.”

Option Compare Binary and Option Compare Text

These two variations of the Option Compare statement instruct your code to use specific sorting rules for certain string comparison features. In general, Binary comparisons are case-sensitive, whereas Text comparisons are not. It’s up to you which method you want to use; the default is Binary.

These statements appear at the top of each source code file in your project, before any other code:

Option Explicit On
Option Strict On

Or, to save on precious disk space, set default values that apply to your entire project through the project’s properties. In Visual Studio, select the Project → Properties menu command. On the project’s properties window that appears, select the Compile tab, and set your default choices for the “Option explicit,” “Option strict,” “Option compare,” and “Option infer” fields (see Figure 2-2).

Options, options everywhere

Figure 2-2. Options, options everywhere

Basic Operators

Visual Basic includes several basic operators that let you do what your code really wants to do: manipulate data. To use them, just dial zero from your phone. No, wait; those operators let you place operator-assisted calls for only $2.73 for the first minute. The Visual Basic operators let you perform mathematical, logical, bitwise, and string management functions, all at no additional cost.

The most basic operator is the assignment operator, represented by the equals sign (=). You’ve already seen this operator in use in this chapter. Use it to assign some value to a variable (or constant); whatever appears to the right of the operator gets assigned to the reference type or value type variable on the left. The statement:

fiveSquared = 25

assigns a value of 25 to the variable fiveSquared.

Most operators are binary operators—they operate on two distinct values, one to the operator’s left and one to the right; the result is a single calculated value. It’s as though the calculation is fully replaced by the calculated result. For instance, the addition operation:

seven = 3 + 4

becomes:

seven = 7

before the final application of the assignment (=) operator. A unary operator appears just to the left of its operand. For instance, the unary negation operator turns a positive number into a negative number:

negativeSeven = −7

I’ll comment on each operator in detail in Chapter 6. But we’ll need a quick summary for now so that we can manipulate data before we get to that chapter. Table 2-2 lists the main Visual Basic operators and briefly describes the purpose of each one.

Table 2-2. Visual Basic operators

Operator

Description

[a]

+

The addition operator adds two numbers together.

+

The unary plus operator retains the sign of a numeric value. It’s not very useful until you get into operator overloading, something covered in Chapter 12.

The subtraction operator subtracts the second operand from the first.

The unary negation operator reverses the sign of its associated numeric operand.

*

The multiplication operator multiplies two numeric values together.

/

The division operator divides the first numeric operand by the second, returning the quotient including any decimal remainder.

The integer division operator divides the first numeric operand by the second, returning the quotient, but with the decimal remainder truncated.

Mod

The modulo operator divides the first numeric operand by the second, and returns only the remainder as an integer value.

^

The exponentiation operator raises the first operand (the base) to the power of the second (the exponent).

&

The string concatenation operator joins two string operands together, and returns a new string with the combined results.

And[a]

The conjunction operator returns True if both Boolean operands are also True.

AndAlso

This operator is just like the And operator, but it doesn’t examine or process the second operand if the first one is False.

Or[a]

The disjunction operator returns True if either of the operands is also True.

OrElse

This operator is just like the Or operator, but it doesn’t examine or process the second operand if the first one is True.

Not[a]

The negation operator returns the opposite of a Boolean operand.

Xor[a]

The exclusive or operator returns True if exactly one of the operands is also True.

<<

The shift left operator shifts the individual bits in an integer operand to the left by the number of bit positions in the second operand.

>>

The shift right operator shifts the individual bits of an integer operand to the right by the number of bit positions in the second operand.

=

The equal-to comparison operator returns True if the operands are “equal” to each other.

<

The less-than comparison operator returns True if the first operand is “less than” the second.

<=

The less-than-or-equal-to comparison operator returns True if the first operand is “less than or equal to” the second.

>

The greater-than comparison operator returns True if the first operand is “greater than” the second.

>=

The greater-than-or-equal-to comparison operator returns True if the first operand is “greater than or equal to” the second.

<>

The not-equal-to comparison operator returns True if the first operand is “not equal to” the second.

Like

The pattern comparison operator returns True if the first operand matches a string pattern specified by the second operand.

Is

The object equal-to comparison operator returns True if both operands truly represent the same instance of a data value in memory. Setting the second operand to Nothing lets you test a reference variable to see whether it contains data.

IsNot

The object not-equal-to comparison operator is the opposite of the Is operator.

[a] The And, Or, Not, and Xor operators also work as “bitwise” operators. I’ll talk about that in “Operators” in Chapter 6.

As powerful as operators are, they possess even more power when you combine them. This works because any of the operands can be a complex expression that includes its own operands. Parentheses grouped around clauses in operands ensure that values are processed in the order you expect.

circleArea = pi * (radius ^ 2)

In this statement, the second operand of the * multiplication operator is another expression, which includes its own operator.

Using Functions and Subroutines

Years ago I worked for a software company that sometimes published software developed outside the organization, all for a non-Windows platform. While most of these programs were written in the C language, we also published software written in Pascal, assembly language, and good ol’ BASIC. I inherited one such external application written entirely in BASIC, a program that assisted the user in 3D modeling and graphics rendering. It was a complex program, containing about 30,000 lines of source code. The problem was that it was one large block of 30,000 source code lines. No comments, no variable names longer than a few characters, no extra-strength buffered aspirin product. Just thousands of lines of code with flow control statements jumping this way and that. And, of course, it had a bug.

I was able to move past that event in my life without too much therapy, but at the time it was a shock to see code in that condition. And it was so unnecessary, since that flavor of BASIC was a procedural language, just like C and Pascal. Procedural languages allow you to break your code into named blocks of logic, called procedures. These procedures let you take a “divide and conquer” approach to programming; you write procedures that accomplish a specific logical portion of the code within your entire application, and then access these procedures from other procedures.

Visual Basic includes three types of procedures:

Subroutines

These procedures, also called subprocedures, do a bunch of work and then return to the calling procedure. Data can be sent into the subroutine through its argument list, and some values may come back through that same list, but the procedure does not send an official final result back. A subroutine does its work, and once it is complete, the calling code continues on its merry way.

Functions

Functions are just like subroutines, with one additional feature: you can return a single value or object instance from the function as its official result. Usually, the calling code takes this return value into consideration when it completes its own logic.

Properties

When used, properties actually look like variables. You assign and retrieve values to and from properties just like you would for a variable. However, properties include hidden code, often used to validate the data being assigned to the property.

Subroutines, functions, and properties are the code members of each class or similar type. I’ll delay discussion of properties until a little later in the chapter. For now, let’s enjoy functions and subroutines, which together are also known as methods. Let’s start with subroutines. To call a subroutine, type its name as a statement, followed by a set of parentheses. Any data you need to send to the subroutine goes in the parentheses. For instance, the following subroutine call does some work, passing the ID number of a customer, and a starting date:

DoSomeWork(customerID, startDate)

Each subroutine defines the data type and order of the arguments you pass. This argument list may include one or more optional arguments, which are assigned default values if you don’t include them. A subroutine might also be overloaded, defining different possible argument lists based on the number and data type of the arguments. We’ll encounter a lot of these later.

Functions are a little more interesting since they return a usable value. Often, this value is assigned to a variable:

Dim balanceDue As Boolean
balanceDue = HasOutstandingBalance(customerID)

Then you can do something with this result. If you want, you can ignore the return value of a function, and we already have. The MsgBox function used earlier returns the identity of the on-screen button clicked by the user to close the message box. If you include only an OK button (the default), you probably don’t care which button the user clicks.

MsgBox("Go ahead, click the OK button.")

But you can also capture the result of the button:

whichButton = MsgBox("Click Yes or No.", MsgBoxStyle.YesNo)

In this case, whichButton will be either MsgBoxResult.Yes or MsgBoxResult.No, two of the possible results defined by the MsgBox function.

Conditions

Sometimes you have to make some choices, and conditional expressions will help you do just that. Visual Basic includes support for conditions, which use data tests to determine which code should be processed next.

If Statements

The most common conditional statement is the If statement. It is equivalent to English questions in the form “If such-and-such is true, then do so-and-so.” For instance, it can handle “If you have $20, then you can buy me dinner,” but not “If a train departs Chicago at 45 miles per hour, when will it run out of coal?”

If statements have syntax that spans multiple source code lines:

01  If (hadAHammer = True) Then
02     DoHammer(inTheMorning, allOverThisLand)
03     DoHammer(inTheEvening, allOverThisLand)
04  ElseIf (hadAShovel = True) Then
05     DoShovel(inTheNoontime, allOverThisLand)
06  Else
07     TakeNap(allDayLong, onMySofa)
08  End If

The If statement lets you define branches in your code based on conditions. It is built from three main components:

Conditions

The expression found between the If (or ElseIf) keyword and the Then keyword is the condition. The sample includes two conditions, on lines 01 and 04. Conditions may be simple or complex, but they must always result in a Boolean True or False value. They can include calls to other functions and multiple logical and comparison operators.

If ((PlayersOnTeam(homeTeam) >= 9) And _
      (PlayersOnTeam(visitingTeam) >= 9)) Or _
      (justPracticing = True) Then
   PlayBall(  )
Else
   StadiumLights(turnOff)
End If

The original condition always follows the If keyword. If that conditions fails, you can specify additional conditions following an ElseIf keyword, as on line 04. You may include as many ElseIf clauses as you need. The optional Else condition doesn’t let you specify a test expression. Instead, it matches everything not yet caught by the If or ElseIf clauses. Only one Else clause is allowed per If statement.

Branches

Each condition’s Then keyword is followed by one or more Visual Basic statements that are processed if the associated condition evaluates to True. All statements up to the next Else, ElseIf, or End If are included in that branch’s statement block. You may include any number of statements in a branch block, including additional subordinate If statements. In the sample code, branch lines 02 and 03 are processed if the original hadAHammer condition is true. Line 05 is processed instead if the original condition fails, but the second hadAShovel condition passes. If none of the conditions is True, the Else’s branch, on line 07, executes.

Statement keywords

The If statement is one of several multiline statements in Visual Basic, all of which end with the keyword End followed by the original statement keyword (If in this case). The If statement’s keywords, which give the statement its structure, include If, Then, ElseIf, Else, and End If. All ElseIf and Else clauses and related branches are optional. The simplest If statement includes only an If branch.

If (phoneNumberLength = 10) Then
   DialNumber(phoneNumber)
End If

For conditions with simple single-statement branches and no ElseIf clauses, a single-line alternative can keep your code looking clean.

If (SaveData(  ) = True) Then MsgBox("Data saved.")
If (TimeOfDay >= #13:00#) _
   Then currentStatus = WorkStatus.GoHome _
   Else currentStatus = WorkStatus.BusyWorking

If statements are cool because they make your code more than just a boring set of linear step-by-step instructions that never deviate for any reason. Software is written to support some real-world process, and real-world processes are seldom linear. The If statement makes it possible for your code to react to different data conditions, taking the appropriate branch when necessary.

Once the entire If...End If block completes, processing continues with the next statement that follows the End If statement.

Select Case Statements

Sometimes you might write an If statement that tests a variable against one possible value, then another, then another, then another, and so on:

If (billValue = 1) Then
   presidentName = "Washington"
ElseIf (billValue = 2) Then
   presidentName = "Jefferson"
ElseIf (billValue = 5) Then
   presidentName = "Lincoln"
...

And on it goes, through many more ElseIf clauses. It’s effective, but a little tedious, as your code must specifically test every case. The Select Case statement provides a cleaner alternative for simple value comparisons against a list:

01  Select Case billValue
02     Case 1
03        presidentName = "Washington"
04     Case 2
05        presidentName = "Jefferson"
06     Case 5
07        presidentName = "Lincoln"
08     Case 20
09        presidentName = "Jackson"
10     Case 50
11        presidentName = "Grant"
12     Case 10, 100
13        presidentName = "!! Non-president"
14     Case > 100
15        presidentName = "!! Value too large"
16     Case Else
17        presidentName = "!! Invalid value"
18  End Select

Unlike the If statement, which checks for a Boolean result, Select Case compares a single value against a set of test case values. In the example, the billValue variable is compared against the different values identified by each Case clause. All code that follows a Case clause (until the next Case clause) is the branch that is processed when a match is found. An optional Case Else condition (line 16) catches anything that is not matched by any other Case. Normally, Case clauses list single values for comparison. They can also include a list of comma-separated comparison values (line 12), or simple range comparison expressions (line 14).

IIf and If Functions

Visual Basic includes two variations of the If statement for “inline” use. Consider the following statement:

If (gender = "F") Then fullGender = "Female" _
   Else fullGender = "Male"

Using the IIf function, this statement compresses into a single assignment statement with an embedded condition:

fullGender = IIf(gender = "F", "Female", "Male")

The IIf function has three comma-delimited arguments. The first is the condition, which must result in a Boolean True or False value. The second argument is returned by the function if the condition is True; a condition result of False returns the third argument. For simple conditions that are destined to return single values to a common variable, it’s really a useful function. But with anything really useful, there are caveats. The caveat with IIf is that anything appearing inside the IIf statement will be processed, even if it is not returned as a result. Here’s a dangerous example:

purgeResult = IIf(level = 1, PurgeSet1(  ), PurgeSet2(  ))

The statement will correctly return the result of either PurgeSet1( ) or PurgeSet2( ) based on the value of level. The problem, or potential problem, is that both functions, PurgeSet1( ) and PurgeSet2( ), will be called; if level is 1, both PurgeSet1( ) and PurgeSet2( ) will be called, even though only the function result from PurgeSet1( ) will be returned.

To help avoid such side effects, Visual Basic 2008 added the new If operator. It looks just like the IIf function, except for the keyword If replacing the IIf keyword:

purgeResult = If(level = 1, PurgeSet1(  ), PurgeSet2(  ))

Now only PurgeSet1( ) or PurgeSet2( ) will be called based on the condition, but not both. Although the If operator looks like a function, it is actually a true operator, known as the ternary operator. At compile time, Visual Basic treats it and its arguments as operator and operands and generates the appropriate logic.

A variation of the If operator takes just two arguments, excluding the initial Boolean argument.

realObject = If(object1, object2)

In this version of the If operator, if the first argument evaluates to Nothing, the operator returns the second argument. If the first argument is not Nothing—that is, if it really is something—the operator returns that first argument instead. The goal is to return non-Nothing, although that’s a double negative.

Loops

Visual Basic includes three major types of loops: For...Next, For Each...Next, and Do...Loop. Just as conditions allow you to break up the sequential monotony of your code through branches, loops add to the usefulness of your code by letting you repeat a specific block of logic a fixed or variable number of times.

For . . . Next Loops

The For...Next loop uses a numeric counter that increments from a starting value to an ending value, processing the code within the loop once for each incremented value.

Dim whichMonth As Integer
For whichMonth = 1 To 12
   ProcessMonthlyData(whichMonth)
Next whichMonth

This sample loops 12 times (1 To 12), once for each month. You can specify any starting and ending values you wish; this range can also be specified using variables or functions that return numeric values. Once the starting and ending values are obtained, they are not recalculated each time through the loop, even if a function call is used to obtain one or both limits.

' ----- Month(Today) returns the numeric month
'       for the current date.
For whichMonth = 1 To Month(Today)
   ProcessMonthlyData(whichMonth)
Next whichMonth

Normally, the loop increments by one (1) each time through. You can alter this default by attaching a Step clause to the end of the For statement line:

For countDown = 60 To 0 Step −1
   ...
Next countDown

One additional syntax variation allows you to declare the loop counter variable within the statement itself. Such variables are available only within the loop, and cease to exist once the loop exits.

For whichMonth As Integer = 1 To 12
   ProcessMonthlyData(whichMonth)
Next whichMonth

For Each . . . Next Loops

A variation of the For loop, the For Each...Next loop scans through a set of ordered and related items, from the first item until the last. Arrays and collection objects also work, as does any object that supports the IEnumerable interface (all these topics are covered in Chapter 6). The syntax is quite similar to the standard For statement:

For Each oneRecord In setOfRecords
   ProcessRecord(oneRecord)
Next oneRecord

Do . . . Loop Loops

Sometimes you want to repeat a block of code as long as a certain condition is true, or only until a condition is true. The Do...Loop structure performs both of these tasks. The statement includes a While or Until clause that specifies the conditions for continued loop processing. For instance, the following statement does some processing for a set of dates, from a starting date to an ending date:

Dim processDate As Date = #1/1/2000#
Do While (processDate < #2/1/2000#)
   ' ----- Perform processing for the current date.
   ProcessContent(processDate)

   ' ----- Move ahead to the next date.
   processDate = processDate.AddDays(1)
Loop

Processing in this sample will continue until the processDate variable meets or exceeds 2/1/2000, which indicates the end of processing. The Until clause version is somewhat similar, although with a reversed condition result:

Do Until (processDate >= #2/1/2000#)
   ...
Loop

Make the included condition as simple or as complex as you need. Putting the Until or While clause at the bottom of the loop guarantees that the statements inside the loop will always be processed at least once:

Do
   ...
Loop Until (processDate >= #2/1/2000#)

If the loop condition is never met, the loop will continue forever. So, if you want your loop to exit at some point (and usually you do), make sure the condition can eventually be met.

There is another loop that is similar to Do...Loop, called the While...End While loop. However, it exists for backward compatibility only. Use the Do...Loop statement instead.

Exit Statements

Normally, when you enter a loop, you have every intention of looping for the full number of times specified by the initial conditions of the loop. For For loops, you expect to continue through the entire numeric range or collection of elements. In Do loops, you plan to keep the loop going as long as the exiting condition has not yet been met. But there may be loops that you want to exit early. You accomplish this using an Exit statement.

There are two loop-specific Exit statements:

Exit For

Exits a For...Next or For Each...Next loop immediately

Exit Do

Exits a Do...Loop statement immediately

Each Exit statement exits the loop that contains the statement; processing continues with the line immediately following the loop:

For whichMonth = 1 To 12
   If (ProcessMonthlyData(whichMonth) = False) Then Exit For
Next whichMonth
' ----- Code continues here no matter how the loop was exited.

The sample code is designed to loop through all 12 months. However, a processing failure for any of the 12 months will immediately exit the loop, abandoning all remaining month processing actions. The Exit Do statement similarly exits Do...Loop loops immediately.

In an Exit loop statement within nested loops (where one loop appears within another), only the matching loop that immediately contains the statement is exited:

For whichMonth = 1 To 12
   For whichDay = 1 to DaysInMonth(whichMonth)
      If (ProcessDailyData(whichMonth, whichDay) = False) _
         Then Exit For
   Next whichDay
   ' ----- The Exit For statement jumps to this line.
   '       Processing continues with the next month.
Next whichMonth

Continue Statements

Since exiting a loop abandons all remaining passes through the loop, you may miss out on important processing that would have happened in subsequent passes. Visual Basic includes a Continue statement that lets you abandon only the current pass through the loop.

There are different Continue statement variations for each loop type:

Continue For

Immediately jumps to the end of the For...Next or For Each...Next loop and prepares for the next pass. The loop variable is incremented and compared with the range or collection limits.

Continue Do

Immediately jumps to the end of the Do...Loop statement and prepares for the next pass. The Until or While condition is reevaluated.

Since the loop conditions are re-evaluated when using the Continue statements, there are times when Continue may cause the loop to exit, such as when it had been the final pass through the loop already.

In this example, the Continue For statement skips processing for months that have no data to process:

For whichMonth = 1 To 12
   If (DataAvailable(whichMonth) = False) Then Continue For
   RetrieveData(whichMonth)
   ProcessData(whichMonth)
   SaveData(whichMonth)
Next whichMonth

Creating Your Own Procedures

All logic statements in your code must appear within a procedure, whether in a subroutine, a function, or a property. Although there are thousands of prewritten procedures for you to choose from in the .NET Framework libraries, you can also add your own.

Subroutines

Subroutines begin with a Sub declaration statement and end with an End Sub statement. All of your subroutine’s logic appears in between these two mighty jaws.

01  Sub ShowIngredients(ByVal gender As Char)
02     Dim theMessage As String = "Unknown."
03     If (gender = "M"c) Then
04        theMessage = "Snips and snails and puppy dog tails."
05     ElseIf (gender = "F"c) Then
06        theMessage = "Sugar and spice and everything nice."
07     End If
08     MsgBox(theMessage)
09  End Sub

Line 01 shows the subroutine’s declaration line in its simplest form; throughout the book, you will find that there are additional keywords that decorate procedure declarations to change their behavior. The statement begins with the Sub keyword (for subroutine), followed by the name of the procedure, ShowIngredients.

The parentheses following this name contain the subroutine’s parameters. Parameters allow another block of code that will use this procedure to pass data into the procedure, and optionally receive data back. You can include any number of parameters in the subroutine definition; simply separate them by commas. Each parameter specifies the name as it will be used in the procedure (gender in the sample) and its data type (Char). The arguments are treated as declared variables within the procedure, as is done with gender on lines 03 and 05.

The values supplied by the calling code are known as arguments. All arguments are passed by value or by reference. In the sample code, the argument passed into gender will be passed by value, as specified through the ByVal keyword. The related ByRef keyword indicates an argument to be passed by reference. If you don’t include either keyword, ByVal is assumed. This passing method impacts whether changes made to the argument within the local procedure are propagated back to the calling code. However, the ability to update the original data is also influenced by whether the data is a value type or a reference type. Table 2-3 indicates the behavior for each combination of passing method and data type.

Table 2-3. Updating data, the .NET way

Passing method

Data type

Behavior

ByVal

Value type

Changes made to the local version of the argument have no impact on the original version.

ByVal

Reference type

Changes made to members of the data object immediately impact the original data object. However, the object itself cannot be changed or replaced with a completely new data object.

ByRef

Value type

Changes made to the local version are returned to the calling procedure, and permanently impact the original data value.

ByRef

Reference type

Changes made to either the data object or its members are also changed in the original. It is possible to fully replace the object sent into the procedure.

In most cases, if you are interested in modifying the value of a parameter and having the changes return to the caller, use ByRef; otherwise, use ByVal.

Lines 02 through 08 in the sample code comprise the body of the procedure, where all your logic appears. Any variables to be used solely in the routine are also defined here, as with the theMessage variable on line 02. The subroutine always concludes with an End Sub statement.

Functions

The syntax of a function differs only slightly from subroutines, to support a return value.

01  Function IsPrime(ByVal source As Long) As Boolean
02     ' ----- Determine whether source is a prime number.
03     Dim testValue As Long
04     If (source < 2) Then
05        Return False
06     ElseIf (source > 2) Then
07        For testValue = 2 To source  2&
08           If ((source Mod testValue) = 0) Then
09              Return False
10           End If
11        Next testValue
12     End If
13     Return True
14  End Function

As with subroutines, the function’s declaration line appears first (line 01), followed by the body (lines 02 through 13) and the closing End Function statement (line 14). The declaration line includes an extra data type definition after the parameter list. This is the data type of the final value to be returned to the calling code. Use this return value in the calling code just like any other value or variable. For example, the following line calls the IsPrime function and stores its Boolean result in a variable:

primeResult = IsPrime(23)

To indicate the value to return, use the Return statement (described later in the chapter). The sample code does this on lines 05, 09, and 13. (An older VB 6.0 syntax that lets you assign the return value to the name of the function still works.)

Properties

A little earlier I mentioned fields, which are variables or constants that appear within a class, but outside any procedure definition.

01  Class PercentRange
02     Public Percent As Integer
03  End Class

Properties are similar to fields; they are used like class-level variables or constants. But they are programmed like functions, accepting parameters, having return values, and including as much logic as you require.

Properties are often used to protect private class data with logic that weeds out inappropriate values. The following class defines a single property that provides access to the hidden related field:

01  Class PercentRange
02     ' ----- Stores a percent from 0 to 100 only.
03     Private savedPercent As Integer
04     Public Property Percent(  ) As Integer
05        Get
06           Return savedPercent
07        End Get
08        Set(ByVal value As Integer)
09           If (value < 0) Then
10              savedPercent = 0
11           ElseIf (value > 100) Then
12              savedPercent = 100
13           Else
14              savedPercent = value
15           End If
16        End Set
17     End Property
18  End Class

The Percent property (lines 04 to 17) protects access to the savedPercent field (line 03), correcting any caller-supplied values that exceed the 0 to 100 range. Properties include separate assignment and retrieval components, also called accessors. The Get accessor (lines 05 to 07) returns the property’s monitored value to the caller. The Set accessor (lines 08 to 16) lets the caller modify the value of the property.

The property declaration statement (line 04) includes a data type that matches the data type passed into the Set accessor (line 08). This is the data type of the value set or retrieved by the caller. To use this sample Percent property, create an instance of the PercentRange class, and then use the property:

Dim activePercent As New PercentRange
activePercent.Percent = 107    ' An out-of-range Integer
MsgBox(activePercent.Percent)  ' Displays "100", not "107"

You can create read-only or write-only properties by including the ReadOnly or WriteOnly keyword just before the Property keyword in the declaration statement (line 04), and leaving out the unneeded accessor.

Properties do not need to be tied to fields. You can use properties to get and set any type of value, and store it or act upon it in any manner you wish.

Where to Put Your Procedures

Back in the good ol’ days of Visual Basic 6.0, procedures could appear just about anywhere in your source code files. You would open a source file, type a function, and go; it was that easy. With the move to .NET, all Visual Basic procedures must now appear within a defined class (or a structure or module).

Class Employee
   Sub StartVacation(  )
      ...
   End Sub

   Function TotalVacationTaken(  ) As Double
      ...
   End Function
End Class

When you create instances of your class later in code, the methods can be called directly through the object instance.

Dim executive As New Employee
...
executive.StartVacation(  )

Chapter 8 shows you how to use and build classes.

Other Flow Control Features

The loops and conditional statements available in Visual Basic let you reroute your code based on data. The language includes a few other statements that let you control the action in a more direct manner.

The GoTo Statement

The GoTo statement lets you jump immediately to some other location within the current procedure. The destination of a jump is always a line label, a named line position in the current procedure. All line labels appear at the start of a logical line, and end with a colon.

PromptUser:
   GetValuesFromUser(numerator, denominator)
   If (denominator = 0) Then GoTo PromptUser
   quotient = numerator / denominator

In this sample, the GoTo statement jumps back to the PromptUser label when the code detects invalid data. Processing continues with the line immediately following the PromptUser label. You can’t use the same label name twice in the same procedure, although you can reuse label names in different procedures. If you want, include another logic statement on the same line as your label, right after the colon, although your code will be somewhat easier to read if you keep labels on their own lines.

LabelAlone:
   MsgBox("It's all alone.")
LabelAndCode: MsgBox("Together again.")

It’s all right to include as many labels in your code as you need, but the GoTo statement is one of those elements of Visual Basic that is monitored closely by pesky international software agencies, such as the International Committee to Keep GoTo Always Gone (ICK-GAG). That group also scans computer books looking for derogatory references to its organization name—not that it would find anything like that in this book. But its core issue is that overuse of GoTo statements can lead to spaghetti code, such as the following:

Dim importantMessage As String = "Do"
GoTo Step2
Step6: importantMessage &= "AG!"
GoTo Step7
Step3: importantMessage &= "wit"
GoTo Step4
Step2: importantMessage &= "wn "
GoTo Step3
Step5: importantMessage &= "CK-G"
GoTo Step6
Step4: importantMessage &= "h I"
GoTo Step5
Step7: MsgBox(importantMessage)

Some people say that such code is hard to read. Others call it job security. No matter what you call it, it does make code very hard to maintain and review. You should probably keep an eye on your use of GoTo statements; if you don’t, someone else might.

Visual Basic itself places some limits on the use of GoTo. You cannot jump into or out of certain multiline statements that would result in improperly initialized code or data values. For instance, you cannot jump into the middle of a For...Next statement from outside the statement, since the loop counter variable and the starting and ending ranges would not be properly initialized.

' ----- This GoTo statement will fail.
GoTo InsideTheLoop
For counter = 1 to 10
InsideTheLoop:
   MsgBox("Loop number: " & counter)
Next counter

However, once you are inside the loop, you can jump to line labels that also appear in the loop, and it’s acceptable to jump out of the loop using GoTo. Some other multiline structures impose similar restrictions.

The Return Statement

Not only can you jump around within a procedure using GoTo, but you can also jump right out of a procedure anytime you want using the Return statement. Normally, a procedure exits when processing reaches the last line of code in the procedure; processing then continues with the code that called the procedure. The Return statement provides a way to exit the procedure before reaching the end.

In subroutines, the Return statement appears by itself as a standalone statement:

Return

In functions, the statement must include the value to be returned to the calling code: a variable, a literal, or an expression that must match the specified return value data type of the function.

Return 25

Pre-.NET releases of Visual Basic used an Exit statement to immediately leave a procedure. These are still supported in .NET. There are three variations:

Exit Sub

Exits a subroutine

Exit Function

Exits a function

Exit Property

Exits a property

When exiting from a function, the Exit Function statement does not include a way to specify a return value. You must set the return value separately by assigning the return value to the name of the function.

Function SafeDivide(ByVal numerator As Double, _
      ByVal denominator As Double) As Double
   ' ----- The "#" sign makes a number a Double.
   If (denominator = 0#) Then
      ' ----- Return 0 on invalid division.
      SafeDivide = 0#
      Exit Function
   End If
   Return numerator / denominator
End Function

The End and Stop Statements

The End and Stop statements bring an immediate halt to your Visual Basic application. The End statement exits your program immediately, aborting all further code and data processing (although certain acquired resources are cleaned up).

The Stop statement suspends processing only when you are running your application within a debugger, such as the Visual Studio development environment. Stop returns control to the environment, allowing the developer to examine and possibly alter data and code before continuing on with the program. If a Stop is encountered in a standalone application running outside the debugger, it prompts the user to debug the application using any debugger installed on the workstation. Needless to say, the user will not be amused.

Events and Event Handlers

Visual Basic is an event-driven language. This is especially true of programs written to run on the Windows desktop. After some important initialization, the user is generally in control of all actions in the program. Who knows what the crazy user will do. He might click here. She might type there. It could be all mayhem and bedlam. But whatever the user does, your program will learn about it through events.

Since the first days of Windows, desktop programs have used a message pump to communicate user and system actions to your code. Mouse and keyboard input, system-generated actions, and other notifications from external sources flow into a program’s common message queue. The message pump draws these messages out one by one, examines them, and feeds them to the appropriate areas of your code.

In traditional Windows programming, you craft the message pump yourself, including code that makes direct calls to event-handling procedures based on the message type. In a Visual Basic program (both in .NET and earlier), the language provides the message pump for you. It analyzes the messages as they are pumped out of the message queue, and directs them to the appropriate code. In .NET, this code appears within classes. Once a class has a chance to analyze the message, it can generate an event, which is ultimately processed by an event handler, a subroutine you write to respond to the action. This calling of the event handler is known as firing an event. So, there are two parts of an event: (1) some code that decides to fire the event; and (2) an event handler that responds to the fired event.

Events are really just indirect calls to a procedure. Instead of having the main code call another subroutine directly, it asks .NET to call the other subroutine for it, passing specific arguments that the calling code may wish to include. So, why would you want to do this instead of just making the subroutine call directly? For one thing, this indirect method lets you add event handlers long after the initial event-firing code was written. This is good, since the event-firing code may be in a third-party assembly that was written years ago. A second benefit is that one event can target multiple event handlers. When the event fires, each event handler will be called, and each can perform any custom logic found in the handler subroutine.

The code that fires the event passes event-specific data to the target event handler(s) through the handler’s parameter list. For the indirect subroutine call to work, the event handler needs to contain the correct number of arguments, in the right order, each of a specific and expected data type. The Event statement defines this contract between the event and the handler.

Public Event SalaryChanged(ByVal NewSalary As Decimal)

This Event statement defines an event named SalaryChanged with a single argument, a Decimal value. Any event handler wishing to monitor the event must match this argument signature.

Sub EmployeePayChanged(ByVal updatedSalary As Decimal)...

Events can occur for any reason you deem necessary; they need not be tied to user or system actions. In this sample class, an event fires each time a change is made to the employee’s salary. The RaiseEvent statement performs the actual firing of the event, specifying the name of the event to fire, and a set of arguments in parentheses.

Public Class Employee
   Public Name As String
   Private currentSalary As Decimal

   Public Property Salary(  ) As Decimal
      Get
         Return currentSalary
      End Get
      Set(ByVal value As Decimal)
         currentSalary = value
         RaiseEvent SalaryChanged(currentSalary)
      End Set
   End Property

   Public Event SalaryChanged(ByVal NewSalary As Decimal)
End Class

The event handlers are not added directly to the class. Instead, they are attached to an instance of the class. The instance, declared as a class field, must be defined using the special WithEvents keyword, which tells Visual Basic that this instance will process events.

Public WithEvents MonitoredEmployee As Employee

Event handlers are ordinary subroutines, but they include the Handles keyword to indicate which event is being handled.

Private Sub EmployeePayChanged( _
      ByVal updatedSalary As Decimal) _
      Handles MonitoredEmployee.SalaryChanged
   MsgBox("The new salary for " & _
      MonitoredEmployee.Name & " is " & updatedSalary)
End Sub

All that is needed is something to kick off the action.

Public Sub HireFred(  )
   MonitoredEmployee = New Employee
   MonitoredEmployee.Name = "Fred"
   MonitoredEmployee.Salary = 50000   ' Triggers event
End Sub

When the salary is set, the Employee class’s Salary property fires the SalaryChanged event using the Visual Basic RaiseEvent command. This generates a call to the EmployeePayChanged event handler, which finally displays the message.

The events built into the Windows Forms classes in .NET work just like this, but instead of watching with me for a salary increase, they are watching for mouse clicks and keyboard clacks. All of these system events use a common argument signature.

Event EventName(ByVal sender As System.Object, _
   ByVal e As System.EventArgs)

The sender argument identifies the instance of the object that is firing the event, in case the caller needs to examine its members. The e argument is an object that lets the caller send event-specific data to the handler through a single class instance. The System.EventArgs class doesn’t have much in the way of members, but many events use a substitute class that is derived from System.EventArgs.

As we pass through the chapters of this book, there will be no end to the number of event examples you will see and experience. I will save the more involved and interesting samples until then.

Namespaces

Classes, structures, modules, enumerations, interfaces, and delegates—the major .NET types—don’t just float around in the code of your application. They must all be grouped and managed into namespaces. As described in Chapter 1, namespaces provide a hierarchy for your types, sort of a tree-shaped condominium where each type has a home. Some of those homes (or nodes), such as System, get pretty crowded with all those type families living there. Others, such as System.Timers, may have only a few types dwelling in their ample abodes. But every type must live in the hierarchy; none of the types is adventurous enough to strike out on its own and build a ranch house.

At the very root of the hierarchy is Global, not a node itself, but a Visual Basic keyword that indicates the root of all roots. You can include Global when referencing your namespaces, but its use is required only when leaving it out would cause confusion between two namespace branches.

Directly under Global are the few top-level namespaces, including System and Microsoft. Each top-level namespace contains subordinate namespaces, and each of those can contain additional third-level namespaces, and so on. Namespace nodes are referenced relative to one another using a “dot” notation.

System.Windows.Forms

This specifies the third-level Forms namespace. You could also have typed:

Global.System.Windows.Forms

which means the same thing. Relative namespaces are also supported:

Forms

However, to use relative namespaces, you must tell your Visual Basic code to expect them. There are so many namespaces out there, and there may be several Forms namespaces somewhere in the hierarchy.

Referencing Namespaces

Before namespaces can be used in your code, they must be referenced and optionally imported. Referencing a namespace identifies the DLL assembly file that contains that namespace’s types. Perform both of these actions through the References tab of each project’s Properties form (see Figure 2-3).

References and imports for a project

Figure 2-3. References and imports for a project

Actually, you are not referencing the namespaces in the DLL, but rather the types, all of which happen to live in specific namespaces. However, for the core type DLLs supplied with the .NET Framework, it feels like the same thing. In fact, Microsoft even named many of the DLLs to match the namespaces they contain. System.dll contains types within the System namespace. System.Windows.Forms.dll includes types specific to Windows Forms applications, and all of these types appear in the System.Windows.Forms namespace or one of its subordinates.

If you don’t reference a DLL in your project, none of its types will be available to you in your code. Visual Studio loads several references into your project automatically based on the type of project you create. Figure 2-3 shows the nine default references included within a Windows Forms application: System, System.Core, System.Data, System.Data.DataSetExtensions, System.Deployment, System.Drawing, System.Windows.Forms, System.Xml, and System.Xml.Linq.

Once you have referenced a library of classes (or other types) in your code, access any of its classes by specifying the full namespace to that class. For instance, the class for an on-screen form is referenced by System.Windows.Forms.Form. That’s three levels down into the hierarchy, and some classes are even deeper. I hope that your health insurance plan covers carpal tunnel syndrome.

To avoid typing all those long namespaces over and over again, Visual Basic includes an imports feature. Imports are namespace-specific; once a namespace has been imported, you can access any of the types in that namespace without specifying the namespace name. If you import the System.Windows.Forms namespace, you only have to type “Form” to access the Form class. The bottom half of Figure 2-3 shows how to set these imports through the project’s properties. The “Imported namespaces” list shows all available referenced namespaces. Simply check the ones you wish to import; System.Windows.Forms is already checked for you by default in Windows Forms applications.

You can also import a namespace directly in your source code. Use the Imports statement at the very start of a source code file:

Imports System.Windows.Forms

The Imports statement supports namespace abbreviations, short names that represent the full namespace in your code. Using the statement:

Imports Fred = System.Windows.Forms

lets you reference the Form class as “Fred.Form.” Unlike the imports list in the project’s properties, which impacts the entire project, the Imports statement affects only a single source code file.

Namespaces in Your Project

By default, all the classes and types in your project appear in a top-level namespace that takes on the name of your project. For a Windows Forms application, this default namespace is called WindowsApplication1. To specify a different top-level namespace, modify it through the Application tab of the project’s properties, in the “Root namespace” field. All the types in your project appear in this namespace; if you specify an existing Microsoft-supplied namespace as your project’s root namespace, all your types will appear in that specified namespace mixed in with the preexisting types. For standalone applications, this mixture will be visible only from your code.

From the root namespace, you can place types within subordinate namespaces by using the Namespace statement. Namespace is a block statement that ends with the End Namespace clause. Any types you create between the Namespace and End Namespace clauses will be contained in that subordinate namespace. For example, if your root namespace is WindowsApplication1, the following statements create a class whose full name is WindowsApplication1.WorkArea.BasicStuff.BusyData:

Namespace WorkArea.BasicStuff
   Class BusyData
      ...
   End Class
End Namespace

You can include as many Namespace statements in your code as needed. Nesting of namespaces is also supported:

Namespace WorkArea
   Namespace BasicStuff
      Class BusyData
         ...
      End Class
   End Namespace
End Namespace

The My Namespace

Visual Basic 2005 introduced a new “My” top-level namespace, designed to simplify common programming tasks. Microsoft added it to the language in part to draw holdout Visual Basic 6.0 stalwarts into the .NET fold. But most of it is really not that dramatic. My collects commonly used features that are currently sprinkled around the Framework Class Library (FCL), and puts them in a mini-hierarchy for convenient access. It’s really not much more complicated than that. The hierarchy is nicely organized, with sections for user, application, and computer-specific information. It’s used just like any other part of the framework, although you cannot use the Imports keyword to access its components by a relative path.

Overall, My is very easy to use. To display the version number of your application, for instance, use the following statement:

MsgBox(My.Application.Info.Version.ToString)

Some areas of the My namespace are dynamic; classes are added or removed as you modify your source code. In Windows Forms applications, the My.Forms branch includes entries for each one of the project’s forms. As you add new forms, new entries are added automatically. The My.Forms object then makes a reference to each form available for use in your code.

My.Forms.Form1.Text = "Welcome"

Summary

Sadly, this chapter has reached its conclusion. You may feel that it went by all too fast; you may feel that you didn’t really learn how to write Visual Basic programs; you may feel that a mild sedative would be right just about now. But don’t fret. This chapter served as an introduction to the syntax and major features of Visual Basic. Now begins the deeper training. As we start this book’s main focus—the Library Project—you will encounter specific examples of all features covered only briefly in this chapter.

Project

In this chapter, we will use the Code Snippets feature of Visual Studio to insert source code into a basic sample code framework. Code Snippets is essentially a hierarchical database of saved source code text. If you have installed the code for this book, you will find code snippets for most chapters included right in Visual Studio. In this chapter’s project, I will show you how to use them to add chapter-specific code into your project.

Since we haven’t officially started the Library Project, this chapter’s project will simply extend the “Hello, World!” project we developed in Chapter 1, but with fun parts added. I will include some of the language features we discovered throughout this chapter.

PROJECT ACCESS

Load the Chapter 2 (Before) Code project, either through the New Project templates or by accessing the project directly from the installation directory. To see the code in its final form, load Chapter 2 (After) Code instead.

Each chapter’s sample code includes a “Before” and “After” version. The “After” version represents the code as it will look when all the changes in that chapter’s "Project" section have been applied. The “Before” version doesn’t have any of the chapter’s project changes included, just placeholders where you will insert the code, one block at a time.

Like the project in Chapter 1, this chapter’s project includes a basic Windows form with a single button on it. Clicking on the button displays the same “Hello, World!” message. However, this time, the message starts in an encoded form, and a separate class decodes the message and triggers an event that displays the form.

Once the project is open, view the source code attached to Form1. It should look somewhat like the following:

Public Class Form1
   ' *** Insert Code Snippet #2 here.

   Private Sub Button1_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button1.Click
      ' *** Insert Code Snippet #3 here.
   End Sub

   ' *** Insert Code Snippet #4 here.
End Class

' *** Insert Code Snippet #1 here.

This sample uses a separate class to process the displayed message. The code for this class appears as snippet number 1. To insert the snippet, move the cursor just after the #1 snippet marker line, which reads:

' *** Insert Code Snippet #1 here.

To insert a snippet through the Visual Studio menus, select Edit → IntelliSense → Insert Snippet. The equivalent keyboard sequence is Ctrl-K, Ctrl-X. Or type a question mark (?) anywhere in the source code, followed by pressing the Tab key. Any of these methods displays the first level of snippets (see Figure 2-4).

Snip, snip, snip

Figure 2-4. Snip, snip, snip

From the snippet list, select Programming Visual Basic 2008, and then select Chapter 2. A list of the available snippet items for this chapter appears (see Figure 2-5).

Item, item, item

Figure 2-5. Item, item, item

Finally, select Item 1. The content magically appears within the source code. All insertions of code snippets throughout this book occur in exactly this way.

Snippet 1 inserts the SayHello class, part of the HelloStuff namespace, a portion of which appears here:

Namespace HelloStuff
   Friend Class SayHello
      Private secretMessage As String
      Private reverseFlag As Boolean
      Private decoded As Boolean

      Public Event MessageDecoded( _
         ByVal decodedMessage As String)

      Public Sub New(ByVal codedMessage As String, _
            ByVal reverseIt As Boolean)
         ...

      Public Sub DecodeMessage(ByVal rotationFactor As Integer)
         ...

      Public Sub ReportMessage(  )
         ...
   End Class
End Namespace

The SayHello class includes three private fields (secretMessage, reverseFlag, and decoded), which monitor the current status of the display message. A constructor (New) allows the user to create a new instance of SayHello with an initial message text, and a flag that indicates whether the text should be reversed before display. The DecodeMessage subroutine converts each letter of the encoded message to its final form by shifting each letter a rotationFactor number of places. If the letter E appears and rotationFactor is 3, the letter E is shifted three spaces forward, to H. A negative rotation factor shifts the letters lower in the alphabet. The alphabet wraps at the A-Z boundary. Only letters are rotated, and upper- and lowercase are handled independently.

The ReportMessage method fires the MessageDecoded event, sending the previously decoded message to the event as an argument. So, where is this event handler? It’s attached to an instance of SayHello that will be added to the Form1 class.

INSERT SNIPPET

Insert Chapter 2, Snippet Item 2.

Private WithEvents HelloDecoder As HelloStuff.SayHello

The HelloDecoder class is an instance of the HelloStuff.SayHello class that we just wrote, and the snippet makes it a member of the Form1 class. The WithEvents keyword says, “This instance will respond to events”; specifically, the MessageDecoded event from the SayHello class.

Let’s add the code that triggers the message to display when the user clicks on the on-form button. This occurs in the button’s click event.

INSERT SNIPPET

Insert Chapter 2, Snippet Item 3.

HelloDecoder = New HelloStuff.SayHello("!iqwtB, tqqjM", True)
HelloDecoder.DecodeMessage(-5)
HelloDecoder.ReportMessage(  )

These three lines create an instance of the SayHello class, storing it in the HelloDecoder class field. Can’t read the first argument in the constructor? It’s encoded! It’s a secret! And the True flag says that it’s been reversed to make it an even bigger secret (you don’t know what it is!). The DecodeMessage removes the secrets by shifting each letter as needed, although the reversal doesn’t happen until the call to ReportMessage.

The ReportMessage method doesn’t actually display the message. Instead, it fires an event that makes the unscrambled message available to an event handler.

INSERT SNIPPET

Insert Chapter 2, Snippet Item 4.

Private Sub HelloDecoder_MessageDecoded( _
      ByVal decodedMessage As String) _
      Handles HelloDecoder.MessageDecoded
   ' ----- Show the decoded message.
   MsgBox(decodedMessage)
End Sub

The Handles keyword connects the subroutine with the fired event. The decoded message comes into the handler through the decodedMessage argument, and is splashed all over the screen with a simple yet powerful call to the MsgBox function.

That’s it for the sample code. Now it’s time to roll up your sleeves and embark on a full Visual Basic 2008 project.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.73.102