- •Using Your Sybex Electronic Book
- •Acknowledgments
- •Contents at a Glance
- •Introduction
- •Who Should Read This Book?
- •How About the Advanced Topics?
- •The Structure of the Book
- •How to Reach the Author
- •The Integrated Development Environment
- •The Start Page
- •Project Types
- •Your First VB Application
- •Making the Application More Robust
- •Making the Application More User-Friendly
- •The IDE Components
- •The IDE Menu
- •The Toolbox Window
- •The Solution Explorer
- •The Properties Window
- •The Output Window
- •The Command Window
- •The Task List Window
- •Environment Options
- •A Few Common Properties
- •A Few Common Events
- •A Few Common Methods
- •Building a Console Application
- •Summary
- •Building a Loan Calculator
- •How the Loan Application Works
- •Designing the User Interface
- •Programming the Loan Application
- •Validating the Data
- •Building a Math Calculator
- •Designing the User Interface
- •Programming the MathCalculator App
- •Adding More Features
- •Exception Handling
- •Taking the LoanCalculator to the Web
- •Working with Multiple Forms
- •Working with Multiple Projects
- •Executable Files
- •Distributing an Application
- •VB.NET at Work: Creating a Windows Installer
- •Finishing the Windows Installer
- •Running the Windows Installer
- •Verifying the Installation
- •Summary
- •Variables
- •Declaring Variables
- •Types of Variables
- •Converting Variable Types
- •User-Defined Data Types
- •Examining Variable Types
- •Why Declare Variables?
- •A Variable’s Scope
- •The Lifetime of a Variable
- •Constants
- •Arrays
- •Declaring Arrays
- •Initializing Arrays
- •Array Limits
- •Multidimensional Arrays
- •Dynamic Arrays
- •Arrays of Arrays
- •Variables as Objects
- •So, What’s an Object?
- •Formatting Numbers
- •Formatting Dates
- •Flow-Control Statements
- •Test Structures
- •Loop Structures
- •Nested Control Structures
- •The Exit Statement
- •Summary
- •Modular Coding
- •Subroutines
- •Functions
- •Arguments
- •Argument-Passing Mechanisms
- •Event-Handler Arguments
- •Passing an Unknown Number of Arguments
- •Named Arguments
- •More Types of Function Return Values
- •Overloading Functions
- •Summary
- •The Appearance of Forms
- •Properties of the Form Control
- •Placing Controls on Forms
- •Setting the TabOrder
- •VB.NET at Work: The Contacts Project
- •Anchoring and Docking
- •Loading and Showing Forms
- •The Startup Form
- •Controlling One Form from within Another
- •Forms vs. Dialog Boxes
- •VB.NET at Work: The MultipleForms Project
- •Designing Menus
- •The Menu Editor
- •Manipulating Menus at Runtime
- •Building Dynamic Forms at Runtime
- •The Form.Controls Collection
- •VB.NET at Work: The DynamicForm Project
- •Creating Event Handlers at Runtime
- •Summary
- •The TextBox Control
- •Basic Properties
- •Text-Manipulation Properties
- •Text-Selection Properties
- •Text-Selection Methods
- •Undoing Edits
- •VB.NET at Work: The TextPad Project
- •Capturing Keystrokes
- •The ListBox, CheckedListBox, and ComboBox Controls
- •Basic Properties
- •The Items Collection
- •VB.NET at Work: The ListDemo Project
- •Searching
- •The ComboBox Control
- •The ScrollBar and TrackBar Controls
- •The ScrollBar Control
- •The TrackBar Control
- •Summary
- •The Common Dialog Controls
- •Using the Common Dialog Controls
- •The Color Dialog Box
- •The Font Dialog Box
- •The Open and Save As Dialog Boxes
- •The Print Dialog Box
- •The RichTextBox Control
- •The RTF Language
- •Methods
- •Advanced Editing Features
- •Cutting and Pasting
- •Searching in a RichTextBox Control
- •Formatting URLs
- •VB.NET at Work: The RTFPad Project
- •Summary
- •What Is a Class?
- •Building the Minimal Class
- •Adding Code to the Minimal Class
- •Property Procedures
- •Customizing Default Members
- •Custom Enumerations
- •Using the SimpleClass in Other Projects
- •Firing Events
- •Shared Properties
- •Parsing a Filename String
- •Reusing the StringTools Class
- •Encapsulation and Abstraction
- •Inheritance
- •Inheriting Existing Classes
- •Polymorphism
- •The Shape Class
- •Object Constructors and Destructors
- •Instance and Shared Methods
- •Who Can Inherit What?
- •Parent Class Keywords
- •Derived Class Keyword
- •Parent Class Member Keywords
- •Derived Class Member Keyword
- •MyBase and MyClass
- •Summary
- •On Designing Windows Controls
- •Enhancing Existing Controls
- •Building the FocusedTextBox Control
- •Building Compound Controls
- •VB.NET at Work: The ColorEdit Control
- •VB.NET at Work: The Label3D Control
- •Raising Events
- •Using the Custom Control in Other Projects
- •VB.NET at Work: The Alarm Control
- •Designing Irregularly Shaped Controls
- •Designing Owner-Drawn Menus
- •Designing Owner-Drawn ListBox Controls
- •Using ActiveX Controls
- •Summary
- •Programming Word
- •Objects That Represent Text
- •The Documents Collection and the Document Object
- •Spell-Checking Documents
- •Programming Excel
- •The Worksheets Collection and the Worksheet Object
- •The Range Object
- •Using Excel as a Math Parser
- •Programming Outlook
- •Retrieving Information
- •Recursive Scanning of the Contacts Folder
- •Summary
- •Advanced Array Topics
- •Sorting Arrays
- •Searching Arrays
- •Other Array Operations
- •Array Limitations
- •The ArrayList Collection
- •Creating an ArrayList
- •Adding and Removing Items
- •The HashTable Collection
- •VB.NET at Work: The WordFrequencies Project
- •The SortedList Class
- •The IEnumerator and IComparer Interfaces
- •Enumerating Collections
- •Custom Sorting
- •Custom Sorting of a SortedList
- •The Serialization Class
- •Serializing Individual Objects
- •Serializing a Collection
- •Deserializing Objects
- •Summary
- •Handling Strings and Characters
- •The Char Class
- •The String Class
- •The StringBuilder Class
- •VB.NET at Work: The StringReversal Project
- •VB.NET at Work: The CountWords Project
- •Handling Dates
- •The DateTime Class
- •The TimeSpan Class
- •VB.NET at Work: Timing Operations
- •Summary
- •Accessing Folders and Files
- •The Directory Class
- •The File Class
- •The DirectoryInfo Class
- •The FileInfo Class
- •The Path Class
- •VB.NET at Work: The CustomExplorer Project
- •Accessing Files
- •The FileStream Object
- •The StreamWriter Object
- •The StreamReader Object
- •Sending Data to a File
- •The BinaryWriter Object
- •The BinaryReader Object
- •VB.NET at Work: The RecordSave Project
- •The FileSystemWatcher Component
- •Properties
- •Events
- •VB.NET at Work: The FileSystemWatcher Project
- •Summary
- •Displaying Images
- •The Image Object
- •Exchanging Images through the Clipboard
- •Drawing with GDI+
- •The Basic Drawing Objects
- •Drawing Shapes
- •Drawing Methods
- •Gradients
- •Coordinate Transformations
- •Specifying Transformations
- •VB.NET at Work: Plotting Functions
- •Bitmaps
- •Specifying Colors
- •Defining Colors
- •Processing Bitmaps
- •Summary
- •The Printing Objects
- •PrintDocument
- •PrintDialog
- •PageSetupDialog
- •PrintPreviewDialog
- •PrintPreviewControl
- •Printer and Page Properties
- •Page Geometry
- •Printing Examples
- •Printing Tabular Data
- •Printing Plain Text
- •Printing Bitmaps
- •Using the PrintPreviewControl
- •Summary
- •Examining the Advanced Controls
- •How Tree Structures Work
- •The ImageList Control
- •The TreeView Control
- •Adding New Items at Design Time
- •Adding New Items at Runtime
- •Assigning Images to Nodes
- •Scanning the TreeView Control
- •The ListView Control
- •The Columns Collection
- •The ListItem Object
- •The Items Collection
- •The SubItems Collection
- •Summary
- •Types of Errors
- •Design-Time Errors
- •Runtime Errors
- •Logic Errors
- •Exceptions and Structured Exception Handling
- •Studying an Exception
- •Getting a Handle on this Exception
- •Finally (!)
- •Customizing Exception Handling
- •Throwing Your Own Exceptions
- •Debugging
- •Breakpoints
- •Stepping Through
- •The Local and Watch Windows
- •Summary
- •Basic Concepts
- •Recursion in Real Life
- •A Simple Example
- •Recursion by Mistake
- •Scanning Folders Recursively
- •Describing a Recursive Procedure
- •Translating the Description to Code
- •The Stack Mechanism
- •Stack Defined
- •Recursive Programming and the Stack
- •Passing Arguments through the Stack
- •Special Issues in Recursive Programming
- •Knowing When to Use Recursive Programming
- •Summary
- •MDI Applications: The Basics
- •Building an MDI Application
- •Built-In Capabilities of MDI Applications
- •Accessing Child Forms
- •Ending an MDI Application
- •A Scrollable PictureBox
- •Summary
- •What Is a Database?
- •Relational Databases
- •Exploring the Northwind Database
- •Exploring the Pubs Database
- •Understanding Relations
- •The Server Explorer
- •Working with Tables
- •Relationships, Indices, and Constraints
- •Structured Query Language
- •Executing SQL Statements
- •Selection Queries
- •Calculated Fields
- •SQL Joins
- •Action Queries
- •The Query Builder
- •The Query Builder Interface
- •SQL at Work: Calculating Sums
- •SQL at Work: Counting Rows
- •Limiting the Selection
- •Parameterized Queries
- •Calculated Columns
- •Specifying Left, Right, and Inner Joins
- •Stored Procedures
- •Summary
- •How About XML?
- •Creating a DataSet
- •The DataGrid Control
- •Data Binding
- •VB.NET at Work: The ViewEditCustomers Project
- •Binding Complex Controls
- •Programming the DataAdapter Object
- •The Command Objects
- •The Command and DataReader Objects
- •VB.NET at Work: The DataReader Project
- •VB.NET at Work: The StoredProcedure Project
- •Summary
- •The Structure of a DataSet
- •Navigating the Tables of a DataSet
- •Updating DataSets
- •The DataForm Wizard
- •Handling Identity Fields
- •Transactions
- •Performing Update Operations
- •Updating Tables Manually
- •Building and Using Custom DataSets
- •Summary
- •An HTML Primer
- •HTML Code Elements
- •Server-Client Interaction
- •The Structure of HTML Documents
- •URLs and Hyperlinks
- •The Basic HTML Tags
- •Inserting Graphics
- •Tables
- •Forms and Controls
- •Processing Requests on the Server
- •Building a Web Application
- •Interacting with a Web Application
- •Maintaining State
- •The Web Controls
- •The ASP.NET Objects
- •The Page Object
- •The Response Object
- •The Request Object
- •The Server Object
- •Using Cookies
- •Handling Multiple Forms in Web Applications
- •Summary
- •The Data-Bound Web Controls
- •Simple Data Binding
- •Binding to DataSets
- •Is It a Grid, or a Table?
- •Getting Orders on the Web
- •The Forms of the ProductSearch Application
- •Paging Large DataSets
- •Customizing the Appearance of the DataGrid Control
- •Programming the Select Button
- •Summary
- •How to Serve the Web
- •Building a Web Service
- •Consuming the Web Service
- •Maintaining State in Web Services
- •A Data-Driven Web Service
- •Consuming the Products Web Service in VB
- •Summary
544 Chapter 12 HANDLING STRINGS, CHARACTERS, AND DATES
then the two strings will be:
Mastering VB@@@@@@@@
........Mastering VB
If the string is shorter than the specified field length, then the PadLeft and PadRight methods return the original string. The two padding methods don’t trim the string to fit it in the specified field. You can use the padding methods for visual alignment only if you’re using a monospaced font,
like Courier. These two methods can used to create text files with rows made up of fields with a fixed length.
The StringBuilder Class
The StringBuilder class stores dynamic strings and exposes methods to manipulate them much faster than the String class. To use the StringBuilder class in an application, you must import the System.Text class (unless you want to fully qualify each instance of the StringBuilder class in your code). Assuming you have imported the System.Text class in your code module, you can create a new instance of the class with the following statement:
Dim txt As New StringBuilder
There are many ways to initialize an instance of the StringBuilder class, but first I must explain the capacity of a StringBuilder object. Since the StringBuilder handles dynamic strings, it’s good to declare in advance the size of the string you intend to store in the current instance of the class. The default capacity is 16 characters, and it’s doubled automatically every time you exceed it. To set the initial capacity of the StringBuilder class, use the Capacity property. A related property is the MaxCapacity property, which is read-only and returns the maximum length of a string you can store in a StringBuilder variable. This value is approximately 2 billion characters; it’s the length of the longest string you can store to an instance of the StringBuilder class.
To create a new instance of the StringBuilder class, you can call its constructor without any arguments, as I did in the preceding example. You can also initialize it by passing a string as argument:
Dim txt As New StringBuilder(“some string”)
If you can estimate the maximum length of the string you’ll store in the variable, you can specify this value with the following form of the constructor, so that the variable need not be resized as you add to it:
Dim txt As New StringBuilder(initialCapacity)
The size you specify is not a hard limit; the variable may grow longer at runtime, and the StringBuilder will adjust its capacity.
If you want to specify a maximum capacity for your StringBuilder variable, use the following constructor:
Dim txt As New StringBuilder(initialCapacity, maxCapacity)
Finally, you can initialize a new instance of the StringBuilder class using both an initial and a maximum capacity, as well as its initial value, with the following form of the constructor:
Dim txt As New StringBuilder(string, initialCapacity, maxCapacity)
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
HANDLING STRINGS AND CHARACTERS 545
All the members of the StringBuilder class are instance members. In other words, you must create an instance of the StringBuilder class before calling any of its properties or methods.
Properties
You have already seen the two basic properties of the StringBuilder class, the Capacity and MaxCapacity properties. In addition, the StringBuilder class provides the Length and Chars properties, which are the same as the corresponding properties of the String class.
Length
This property returns the number of characters in the current instance of the StringBuilder and is an integer value smaller than (or, at most, equal to) the Capacity property.
Chars
This property gets or sets the character at a specified location in the string, and it’s an array of characters. Note that the index of the first character is zero.
ch = SB.Chars(index)
where ch is a properly declared Char variable and SB is an instance of the StringBuilder class. To set a character’s value in the string, use the following statement:
SB.Chars(index) = ch
Note The Chars property of the StringBuilder class is read-write, as opposed to the same property of the String class, which is read-only. You can use the Chars array to change selected characters in a string.
Methods
Many of the methods of the StringBuilder class are equivalent to the methods of the String class, but they act directly on the string to which they’re applied, and they don’t return a new, separate string.
Append
The Append method appends a base type to the current instance of the StringBuilder class, and its syntax is
SB.Append(value)
where the value argument can be a single character, a string, a date, or any numeric value. When you append numeric values to a StringBuilder, they’re converted to strings; the value appended is the string returned by the type’s ToString method. You can also append an object to the String- Builder—the actual string that will be appended is the object’s ToString property.
Another form of the Append method allows you to append an array of characters, and it has the following syntax:
SB.Append(chars, startIndex, count)
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
546 Chapter 12 HANDLING STRINGS, CHARACTERS, AND DATES
Or, you can append a segment of a string by specifying the starting location of the substring in the longer string and the number of characters to be copied:
SB.Append(string, startIndex, count)
AppendFormat
The AppendFormat method is similar to the Append method. Before appending the string, however, it formats it. The string to be appended contains format specifications and the appropriate values. The syntax of the AppendFormat method is
SB.AppendFormat(string, values)
The first argument is a string with embedded format specifications and values is an array with values (objects, in general), one for each format specification in the string. If you have a small number of values to format, up to four, you can supply them as separate arguments separated by commas:
SB.AppendFormat(string, value, value, value, value)
The following statement appends the string “Your balance as of Thursday, May 16, 2002 is $19,950.40” to a StringBuilder variable:
Dim statement As New StringBuilder
statement.AppendFormat(“Your balance as of {0:D} is ${1: #,###.00}”, _ #5/16/2002#, 19950.40)
Each format specification is enclosed in a pair of curly brackets, and they’re numbered sequentially (from zero). Then there’s a colon followed by the actual specification. The D format specification tells the AppendFormat method to format the specified string in long date format. The second format specification, “#,###.00”, uses the thousands separator and two decimal digits.
The following statements append the same string, but they pass the values through an array:
Dim statement As New StringBuilder
Dim values() As Object = {“5/16/2002”, 19950.4} statement.AppendFormat(“Your balance as of {0:D} is ${1:#,###.00}”, values)
In both cases, the statement variable will hold a string like this one:
Your balance as of Thursday, May 16, 2002 is $19,950.40
The format specifications in the original string usually contain formatting characters. For more information on date and time formatting options, see the section on the ToString method of the Date type, later in this chapter.
Insert
This method inserts a string into the current instance of the StringBuilder class, and its syntax is
SB.Insert(index, value)
The index argument is the location where the new string will be inserted in the current instance of the StringBuilder, and value is the string to be inserted. As with the Append method, the value argument can be any object. The Insert method will insert the string returned by the object’s ToString method.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
HANDLING STRINGS AND CHARACTERS 547
This means that you can use the Insert method to insert numeric values and dates directly into a StringBuilder variable.
A variation of the syntax shown here inserts multiple copies of the specified string into the StringBuilder:
SB.Insert(index, string, count)
Yet another form of the Insert method inserts an array of characters at the specified location in the current instance of the StringBuilder (chars is an array of characters):
SB.Insert(index, chars)
Remove
This method removes a number of characters from the current StringBuilder, starting at a specified location; its syntax is
SB.Remove(startIndex, count)
where startIndex is the position of the first character to be removed from the string and length is the number of characters to be removed.
Replace
This method replaces all instances of a string in the current StringBuilder with another string. The syntax of the Replace method is
SB.Replace(oldValue, newValue)
where the two arguments can be either strings or characters. Another form of the Replace method limits the replacements to a specified segment of the StringBuilder instance:
SB.Replace(oldValue, newValue, startIndex, count)
This method will replace all instances of oldValue with newValue in the section starting at location startIndex and extending count characters.
ToString
Use this method to convert the StringBuilder instance to a String and assign it to a String variable.
VB.NET at Work: The StringReversal Project
To get an idea of how efficiently the StringBuilder manipulates strings, here’s an application that reverses a string (Figure 12.1). The program reverses two strings, one declared as String and another one declared as StringBuilder. Note that neither the String nor the StringBuilder class exposes a method for reversing the order of the characters in a string. However, you can use the StrReverse() function in this project to reverse a string with a single function call. In this example, we’ll reverse the strings by swapping individual characters to time the two classes.
On my computer, it took a fifth of a second to reverse a 30,000 character-string with the StringBuilder class and almost 14 seconds to do the same with the String class. Obviously, the StringBuilder class is optimized for manipulating strings dynamically. With previous versions of Visual Basic,
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
548 Chapter 12 HANDLING STRINGS, CHARACTERS, AND DATES
many programmers had to write special functions in VC++ to manipulate large strings efficiently. Now, you can get awesome performance out of the StringBuilder class. If you have applications that manipulate strings extensively, port them to VB.NET and watch them run circles around the old applications written with VB’s string-manipulation functions.
Figure 12.1
The StringReversal project’s main form
The StringReversal project reads the text on the TextBox control and appends it to the STR StringBuilder variable. Then it goes through the first half of the string, one character at a time, and swaps it with the matching character in the second half of the array. The first character, STR.Chars(0) is swapped with the last character in the string, STR.Chars(STR.Length-1). The second character, STR.Chars(1), is swapped with the second-to-last character, STR.Chars(STR.Length – 2), and so on. Without the temporary variable, we’d overwrite one of the characters to be swapped and wouldn’t be able to copy it to its new location. Notice that we subtract one from the indices, because the indexing of the characters in a StringBuilder variable starts at zero, and the location of the last character is the length of the string minus 1. By the way, the same is true for String variables. The code stores the length of the StringBuilder to the STRLen variable to avoid calling the Length property at each iteration.
To reverse a String variable, we use the string-manipulation functions of VB. Unlike the methods of the StringBuilder class, the equivalent VB functions use the index 1 for the first character of the string. The Mid() function extracts a character from a string, and the Mid statement replaces one of the existing characters with another one. Listing 12.5 is the Click event handler of the Reverse Text (String) button. You can ignore the statements that time the operations for now—they’re discussed in the following section.
Listing 12.5: Reversing a String Variable
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click Dim TStart, TEnd As Date
Dim TDiff As TimeSpan
Dim STRLen As Integer STRLen = Len(TextBox1.Text) Dim revCrLf As String
revCrLf = vbCrLf.Chars(1) & vbCrLf.Chars(0) TStart = Now()
Dim txt As String txt = TextBox1.Text
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
HANDLING STRINGS AND CHARACTERS 549
Dim aChar As String
Dim iChar As Integer
For iChar = 1 To CInt(STRLen / 2)
aChar = Mid(txt, iChar, 1)
Mid(txt, iChar, 1) = Mid(txt, STRLen - iChar - 1, 1) Mid(txt, STRLen - iChar - 1) = aChar
Next
TEnd = Now()
TDiff = TEnd.Subtract(TStart)
Console.WriteLine(“Reversed string in “ & TDiff.TotalSeconds.ToString) TextBox1.Text = txt.Replace(revCrLf, vbCrLf)
End Sub
Notice the line that replaces carriage returns and line feeds. On the TextBox control, each line is terminated with the sequence Chr(10) & Chr(13). When the order of these two characters is reversed, they will no longer change line on the TextBox control. This statement restores the line- feed/carriage-return combination back to its original state. Listing 12.6 reverses the same string using a StringBuilder variable (this is the code behind the Reverse Text (StringBuilder) button).
Listing 12.6: Reversing a StringBuilder Variable
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click Dim TStart, TEnd As Date
Dim TDiff As TimeSpan
Dim STR As New System.Text.StringBuilder() Dim STRLen As Integer
STRLen = Len(TextBox1.Text) STR.Capacity = STRLen STR.Append(TextBox1.Text) Dim ichar As Integer
Dim chr As Char TStart = Now()
For ichar = 0 To CInt(STR.Length / 2 - 1) chr = STR.Chars(ichar)
STR.Chars(ichar) = STR.Chars(STRLen - ichar - 1) STR.Chars(STRLen - ichar - 1) = chr
Next
Dim revCrLf As String
revCrLf = vbCrLf.Chars(1) & vbCrLf.Chars(0) STR.Replace(revCrLf, vbCrLf)
TEnd = Now()
TDiff = TEnd.Subtract(TStart)
Console.WriteLine(“Reversed string in “ & TDiff.TotalSeconds.ToString) TextBox1.Text = STR.ToString
End Sub
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |