- •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
610 Chapter 13 WORKING WITH FOLDERS AND FILES
Listing 13.20: Reading Records from a Binary File
Private Sub Button2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button2.Click
Dim BR As BinaryReader Dim FS As FileStream
FS = New System.IO.FileStream(“Binarydata2.bin”, FileMode.Open, _ FileAccess.Read)
BR = New System.IO.BinaryReader(FS) BR.BaseStream.Seek(0, SeekOrigin.Begin) Dim p As New Product() TextBox1.Clear()
Dim c As Integer
c = BR.PeekChar
While FS.Position < FS.Length Console.WriteLine(c)
p = Nothing
‘Read fields and populate structure p.ProdID = BR.ReadString p.prodDescription = BR.ReadString p.listPrice = BR.ReadSingle p.available = BR.ReadBoolean p.minStock = BR.ReadInt32
‘Display structure
ShowRecord(p)
c = BR.PeekChar
End While
BR.Close()
FS.Close()
End Sub
Notice that the product’s price is read with the ReadSingle method, because it was saved as a Single variable. The ShowRecord() subroutine appends the fields of the current structure to the TextBox control at the bottom of the form.
Using a custom Structure to store the fields simplifies the structure of the application at large, but it doesn’t help the file I/O operation much. It’s quicker to use the Serializer object to store an entire collection to the file at once, rather than each member of the collection individually. The Serializer object was discussed in Chapter 11, and it addresses many of the file I/O needs of your applications. There will be situations, however, when you must store widely different pieces of information to a text or binary file, and the information presented in this chapter should be adequate for these situations.
The FileSystemWatcher Component
The FileSystemWatcher is a special component that has no visible interface and allows your application to watch for changes in the file system. You can use the FileSystemWatcher component to monitor changes in the local computer’s file system, a network drive, and even a remote computer’s file
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
THE FILESYSTEMWATCHER COMPONENT 611
system (as long as the remote machine is running Windows NT or Windows 2000). The component exposes a few properties that let you specify what type of changes you want to monitor and the folders/files that will be monitored. Once activated, it fires an event every time one of the specified items has been changed.
The items you can monitor are folders and files. You can specify the folders you want to monitor as well as the file types to be monitored. You can also specify the types of actions you want to monitor; each action fires its own event. The actions you can monitor are the creation, deletion, and renaming of a file or folder and the modification of a file. The corresponding events are appropriately named: Changed, Created, Deleted, and Renamed. There’s also a special event, the Error event, that is fired when too many changes occur and the FileSystemWatcher component can’t keep track of them all (the internal buffer overflows and this condition is signaled with the Error event).
Properties
To use a FileSystemWatcher component in your project, open the Components tab of the Toolbox and double-click the FileSystemWatcher component’s icon. An instance of the component will be placed in your project, and you can set the following properties in the Properties window.
NotifyFilter
This property determines the types of changes you want to monitor; its value can have one of the values shown in the Table 13.8, the members of the IO.NotifyFilters enumeration.
Table 13.8: The NotifyFilters Enumeration
Value |
Description |
Attributes |
The attributes of the file or folder |
CreationTime |
The date of file’s or folder’s creation |
DirectoryName |
The directory name |
FileName |
The filename |
LastAccess |
The date of file’s or folder’s last access |
LastWrite |
The date of file’s or folder’s last edit |
Security |
The security settings of the file or folder |
Size |
The size of the file or folder |
|
|
You can combine multiple types of changes with the Or operator, but only in your code. The following statement prepares the FileSystemWatcher1 component to monitor for changes in the date and time of a file’s last write and last access:
FileSystemWatcher1.NotifyFilter = IO.NotifyFilters.LastWrite Or _
IO.NotifyFilters.LastAccess
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
612 Chapter 13 WORKING WITH FOLDERS AND FILES
Path
Set this property to the path you want to monitor. The component will watch for changes in all the files in the specified path. If you want to include the path’s subfolders, set the IncludeSubdirectories property to True. The default value of this property is False.
Filter
This property filters the files you want to monitor through a string with wildcards. A Filter value of *.txt tells the component to monitor for changes in text files only. The default value of the Filter property is *.*, which includes all the files with an extension. To monitor all files, including the ones without extension, set the Filter property to an empty string. Notice that you can’t specify multiple extensions with the Filter property.
EnableRaisingEvents
To start monitoring for changes in the file system, set the EnableRaisingEvents property to True. While the EnableRaisingEvents property is True, the FileSystemWatcher component fires an event for the changes you have specified through its properties.
Events
To notify your application about the changes, the FileSystemWatcher component raises the following events, which you can handle from within your code: Changed, Created, Deleted, and Renamed. To code the handlers of these events, select the name of the FileSystemWatcher component in the Object drop-down list of the editor’s window and the name of the event you want to code in the Events drop-down list.
Like all events, they include two arguments: the sender and the e argument. The second argument of these events carries information about the type of the change through the ChangeType member. The
e.ChangeType member can be a member of the IO.WatcherChangeTypes enumeration: All, Changed,
Created, Deleted, and Renamed. The e.FullPath and e.Name properties are the path and filename of the file that was changed, created, or deleted. In the case of a folder, use the FullPath property to retrieve the name of the changed folder. Finally, the Renamed event’s argument exposes the OldFullPath and OldName members, which let you retrieve the old path and name of the renamed file.
You can write a common event handler for the Changed, Created, and Deleted events, because they share the same arguments. The Rename event must have its own handler, because the e argument is of a different type.
All the changes detected by the FileSystemWatcher component are stored in an internal buffer, which may overflow if too many changes take place in a short period of time. To avoid overflowing the buffer, you should limit the number of files you monitor by setting the Filter and Path properties appropriately. You should always limit the type of changes (you’ll rarely have to monitor for all types of changes in a folder). If the buffer overflows, the Error event will be raised. In this event’s handler you can increase the size of the buffer, by setting the InternalBufferSize property. You can double the buffer’s size from within the Error event handler to prevent the loss of additional events with the following statement:
FileSystemWatcher1.InternalBufferSize = 2 * FileSystemWatcher1.InternalBufferSize
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
THE FILESYSTEMWATCHER COMPONENT 613
VB.NET at Work: The FileSystemWatcher Project
The FileSystemWatcher project, shown in Figure 13.3, demonstrates how to set up a FileSystemWatcher component and how to process the events raised by the component. The FileSystemWatcher component is initialized when the button is clicked. This button’s Click event handler prepares the FileSystemWatcher component to monitor changes in text files on the root of the C: drive. The Path property was set through the Properties window, but you may have to change it. I’ve chosen the root folder because it’s easy to locate and it has very few files on most systems. You can create, edit, rename, and then delete a few text files in the root folder to test the application.
Figure 13.3
The FileSystem-
Watcher project
After setting the properties at design time, the code sets the component’s EnableRaisingEvents property to True to start watching for changes. These changes will be signaled though the component’s events, which are programmed to print in the Output window the type of change detected and the name of the corresponding file. The type of change is reported to the event handler through the ChangeType member of the e argument. When a file is renamed, the program prints both the old and the new name.
The Start Monitoring button is a toggle. When clicked for the first time, its caption changes to Stop Monitoring and if you click it again, it will stop monitoring the file system. The properties of the FileSystemWatcher component are set in the form’s Load event, which is shown in Listing 13.21.
Listing 13.21: Programming the FileSystemWatcher Component
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles MyBase.Load
FileSystemWatcher1.Path = “c:\” FileSystemWatcher1.IncludeSubdirectories = False FileSystemWatcher1.Filter = “*.txt”
FileSystemWatcher1.NotifyFilter = IO.NotifyFilters.CreationTime Or _ IO.NotifyFilters.LastWrite Or IO.NotifyFilters.LastAccess Or _ IO.NotifyFilters.FileName
FileSystemWatcher1.EnableRaisingEvents = False End Sub
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
614 Chapter 13 WORKING WITH FOLDERS AND FILES
The code behind the button’s Click event handler (Listing 13.22) toggles the EnableRaisingEvents property and the button’s caption. When this property is set to True, the FileSystemWatcher component starts monitoring the changes in the file system.
Listing 13.22: The Code of the Start Monitoring Button
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
If Button1.Text = “Start Monitoring” Then
FileSystemWatcher1.EnableRaisingEvents = True
Button1.Text = “Stop Monitoring”
Else
FileSystemWatcher1.EnableRaisingEvents = False
Button1.Text = “Start Monitoring”
End If
End Sub
Now you must program the handlers of the FileSystemWatcher component. You need not program all the events, only the ones you want to monitor. Since the Changed, Created, and Deleted event handlers have the same arguments, you can write a common handler for all three and a separate one for the Renamed event. Listing 13.23 details the event handlers of the sample applications.
Listing 13.23: The Event Handlers of the FileSystemWatcher Component
Private Sub WatcherHandler(ByVal sender As Object, _ ByVal e As System.IO.FileSystemEventArgs) _
Handles FileSystemWatcher1.Changed, FileSystemWatcher1.Created, _ FileSystemWatcher1.Deleted
ListBox1.Items.Add(e.ChangeType & vbTab & e.FullPath) End Sub
Private Sub FileSystemWatcher1_Renamed(ByVal sender As Object, _ ByVal e As System.IO.RenamedEventArgs) _ Handles FileSystemWatcher1.Renamed
ListBox1.Items.Add(e.ChangeType & vbTab & e.OldFullPath & “ TO “ & e.FullPath) End Sub
If you want to handle the Error event, you must stop monitoring the file system momentarily, double the value of the InternalBufferSize property, and then enable the monitoring again, as in Listing 13.24.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |