The Code Behind the Form
One of the first things you are likely to do is to create a new Windows Application project. (A review of other project types is provided later in the section "An Overview of Project Templates.") When you create a new Windows Application project, Visual Studioconfigured for Visual Basic 6 profileswill appear as shown in Figure 1.3.
Figure 1.3. The VS .NET view, with the Visual Basic 6 profile selected, of a new Windows Application project.
Although your view may be a little less crowded than the view captured in the low-resolution figure, the casual observer will quickly recognize Visual Basic. It's not until you switch to the code view of the form that you may get a sinking feeling that something is really, really different here.
For this reason I want to take a few minutes here to help you get accustomed to the radical way VB .NET code looks. (If you have seen Java or C++ code, the VB code in the form won't seem so strange .) Listing 1.4 gives the complete listing of a blank form in a Windows Application project.
Listing 1.4 The code for a form with no controls in Visual Basic .NET
1: Public Class Form1 2: Inherits System.Windows.Forms.Form 3: 4: #Region " Windows Form Designer generated code " 5: 6: Public Sub New() 7: MyBase.New() 8: 9: 'This call is required by the Windows Form Designer. 10: InitializeComponent() 11: 12: 'Add any initialization after the InitializeComponent() call 13: 14: End Sub 15: 16: 'Form overrides dispose to clean up the component list. 17: Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) 18: If disposing Then 19: If Not (components Is Nothing) Then 20: components.Dispose() 21: End If 22: End If 23: MyBase.Dispose(disposing) 24: End Sub 25: 26: 'Required by the Windows Form Designer 27: Private components As System.ComponentModel.IContainer 28: 29: 'NOTE: The following procedure is required by the Windows Form Designer 30: 'It can be modified using the Windows Form Designer. 31: 'Do not modify it using the code editor. 32: <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() 33: ' 34: 'Form1 35: ' 36: Me.AutoScaleBaseSize = New System.Drawing.Size(6, 15) 37: Me.ClientSize = New System.Drawing.Size(292, 268) 38: Me.Name = "Form1" 39: Me.Text = "Form1" 40: 41: End Sub 42: 43: #End Region 44: 45: 46: End Class
The form code contains a lot of information that we never had to see before. The good news is that the code view uses Outlining indicated by the presence of [+] and [-] tags in the code view. A lot of the code between the initial #Region and #End Region is managed by the form. (See the section "The #Region Directive" for more information.) The region with the identifier string "Windows form designer generated code" is the object-oriented code that is working behind the scenes to construct and destruct the form and any controls added to the form.
Using the code-outlining feature of Studio, Listing 1.5 shows the same code with the Form Designer-generated code collapsed .
Listing 1.5 Revision of the code from Listing 1.4, with generated code supporting the Form Designer collapsed using Studio's code outlining feature.
[-]Public Class Form1 Inherits System.Windows.Forms.Form [+][Windows FormDesigner generated code] End Class
In Listing 1.5, I added the code-outlining buttons to show you where the code editor places them. Click the [+] and you will see all the generated code.
Listing 1.5 (with the generated code collapsed) is a little easier to get a handle on, but it still doesn't look like VB6 form code. The first thing you will notice is that the forms are classes, not some hybrid cross between a class and a module. The Public Class Form1 and End Class lines define the class rather than the file that the class is in. The second thing you will notice is that the blank form inherits from the Form class defined in the System.Windows.Forms namespace. (We'll get back to form inheritance later in this chapter.) Next is the generated code. We won't worry about that for now. Finally, you'll notice the End Class statement.
When you define methods and properties for forms, you will write them between the Public Class Form and End Class statements. When you add controls and define event handlers, Visual Studio will add that code in the generated code section. That's really all there is to it. Simply get used to a class, module, or structure block defining the boundaries rather than the file.
Why is it important to make the distinction between the file as class container versus the class idiom as container? The answer is that Visual Basic .NET allows you to define more than one class per file. Listing 1.6 demonstrates a form containing an additional Foo class.
Listing 1.6 Visual Basic .NET allows multiple class definitions per file
1: Public Class Form1 2: Inherits System.Windows.Forms.Form 3: 4: [ Windows Form Designer generated code ] 5: 6: 7: Private Sub Form1_Load(ByVal sender As System.Object, _ 8: ByVal e As System.EventArgs) Handles MyBase.Load 9: 10: Dim F As New Foo() 11: F.ShowName() 12: 13: End Sub 14: 15: #End Region 16: 17: End Class 18: 19: Public Class Foo 20: 21: Public Sub ShowName() 22: MsgBox(Me.GetType().Name) 23: End Sub 24: 25: End Class
Lines 1 through 17 define the class with an added event handler for the OnLoad event. Form1_Load was generated when I double-clicked the Form control. Because the Form OnLoad event handler generated the code, it was placed in the generated section. (Also note that I collapsed most of the generated code to keep the listing short. Lines 19 through 25 are in the same file as the form class definition. Lines 19 through 25 define a second class, Foo, with a single method, ShowName.)
The Form1_load event handler creates a new instance of Foo named F. The Dim statement should look familiar to VB6 programmers. Line 11 calls F.ShowName().
There is a lot of new stuff that I glossed over, such as the presence of arguments for the Form1_Load event handler, the use of the handles keyword at the end of the event handler, and the fact that none of the method calls use the word Call but clearly use parentheses. Listing 1.6 is correct as listed.
Event handlers are implemented as special classes called delegates, or multicast delegates. See Chapter 9, "Understanding Delegates," for more information.
This very brief listing shows some of the changes that might take some getting used to. We will cover them all in time, but for now we have to move on.
Now let's take a look at some of the features you will find in the IDE.
Switching from the Code View to the Object View
If you examine Figure 1.3, you will notice that there is a tab just above the form. These view tabs allow you to switch quickly between the Design view and the Code view. If you open other files or help, these views will be accessible by view tabs too.
Press Ctrl+Tab to cycle from left to right and Ctrl+Shift+Tab to cycle from right to left among all views in either Tabbed Documents or MDI Environment mode.
To switch from the Design view to the Code view, you can also use the F7 key. Press Shift+F7 to switch from Code view to Design view.
Tab views are selected by default in the General tab of the environment options. To change to a multiple document interfaceno tabs, similar to Visual Basic 6choose Tools, Options. In the General view of the Environment Options, change the settings to MDI environment to convert to the older style of form navigation. If you have forgotten how MDI applications work, the MDI environment will display all open views in the Windows menu.
Namespaces have been in use for a while in languages like C++ and Java. Namespaces support a higher classification system than classes. A group of classes can be contained in a namespace, making classes in that namespace distinct from classes with the same name in another namespace. The more code that is shared globally, the more value is derived from namespaces.
Visual Basic .NET uses namespaces. You will see namespaces used in Imports statements or in the Property Pages, Common Properties Imports view. Think of namespaces as a means of adding references to other projects and applications.
A singleton object is a class instantiated only once in a system. The Debug object is an example of a singleton.
For example, the Debug singleton object resides in the System.Diagnostics namespace. You can write the fully qualified name, including the namespace each time you refer to the Debug object, or a better alternative is to add a reference to the namespace. Here is an example of a code fragment written in a click event handler that demonstrates writing some text to the Output window. The first example uses the fully qualified name and the second example requires that the System.Diagnostics namespace be imported.
System.Diagnostics.Debug.WriteLine(_ "Welcome to Valhalla Tower Material Defender!") Debug.WriteLine("This is a test of the emergency broadcast system")
Both examples work because the System.Diagnostics namespace is added as a project Import by default. Of course, the shorter version and importing the namespace is preferable unless there is a conflict between two entities.
The Imports statement takes the following form:
where Imports System.Diagnostics is an example of importing the Diagnostics namespace. Imports statements must precede other declarations but can follow Option statements. I generally place Imports statements at the beginning of a file, immediately after any Option statements.
An even better way to import namespaces is to use the property pages. To add a namespace to the Imports view of the property pages, select the project in the Solution Explorer and select Properties from the right-click context menu (or by choosing Project, Properties). Select the Common Properties folder and the Imports item. Type the name of the namespace you want to import in the Namespace field and click Add Import. The imported namespace should appear in the Project Imports list.
You can enter gibberish for the namespace, and you won't know you have a bad name until you attempt to compile your application.
Code outlining provides you with a convenient means of collapsing and expanding parts of code. You can expand areas of current interest and collapse others depending on the section of code you are focusing on. Figure 1.4 shows the code in an empty form after choosing Edit, Outlining, Collapse to Definitions.
Figure 1.4. The view of an empty form after choosing Edit, Outlining, Collapse to Definitions.
The most direct means of collapsing part of an outline is by clicking the collapse [-] button. To expand an outlined section of code, click the expand [+] button. The outline buttons are added automatically as you add and remove code.
Other outlining features include Hide Selection, Toggle Outlining Expansion, Toggle All Outlining, Stop Outlining, and Stop Hiding Current.
You don't have to expand a hidden block of code to view the contents. Placing the mouse pointer over the  hidden block of code will cause the IDE to display a popup hint containing a formatted view of the collapsed code.
Hide Selection allows you to hide a block of selected code. The selection can span part or all of more than one outlined section. Hide Selection compresses the code to the expand button and an ellipsis in a box. A hidden selection appears roughly as a boxed ellipsis . To unhide a selection, use the Stop Hiding Current menu item.
Toggle Outlining Expansion reverses the current state of the innermost outlined section wherever the cursor is located. Stop Outlining removes the Outlining indicators from the code view, and Collapse to Definitions shows just definitions. For example, if you had a subroutine named Foo, Collapse to Definitions would result in just the subroutine definition being visible, followed by the [...] where the subroutine body is collapsed.
The Edit, Outlining, Toggle All Outlining menu item toggles all code outlining. If code is collapsed, this menu item expands it and vice versa.
The #Region Directive
The #Region directive facilitates code outlining. Regions are useful for organizing your code by regions of importance. For example, you could add a region directive around private members of a class and collapse that region to make it easier to find public methods. The basic format of this directive is as follows :
#Region " identifier string " #End Region
The region can be expanded and collapsed and will have an identifier string to indicate what is in that region. The extra spaces are included to pad the text inside the box in which the text is displayed.
Be thoughtful when you modify code in a #Region directive. This is especially true of the code in a form with the directive
#Region " Windows Form Designer generated code "
This region contains some code that must be defined in the form for it to work correctly, including the New, Dispose, and InitializeComponent subroutines. Generally, code you aren't supposed to modify is preceded by a comment indicating its required status.
Regions can't begin or end inside methods, but you can wrap entire classes or chunks of code within a class in a region.
Code Editing and Documentation Features
The Visual Studio IDE contains several useful features for documenting your code. The IDE supports task lists, the legacy code-commenting features of ' and Remshort for remarka Comment and Uncomment toolbutton that allows you to comment or uncomment multiple lines of code at once, line numbering, and automatic word wrap. Let's go over each of these features to see how to employ them and where they are useful.
TODO Comments and the Task List
Visual Studio provides a Task List feature. The Task List capabilities are summarized in Table 1.1. One of my favorite features is the ' TODO comment tag. Enter a comment using the apostrophe or Rem comment token and precede the text of the comment with the TODO tag; that comment will be added as an item in the Task List. To view TODO comments in the Task List, choose View, Show Tasks , All.
You may add custom tags that are added as prioritized tasks in the Options dialog box. Choose Tools, Options. From the Environment folder, select the Task List view and add a custom token in the Comment Tokens section. Refer to Figure 1.5 for a pictorial guide. In Figure 1.5, I added an EXTRACT_METHOD Comment Token. I use this Comment Token to mark code that needs the Refactoring, Extract Method.
Figure 1.5. Add custom Comment Tokens for task management from the Task List view of the Options dialog box. Choose Tools, Options, Environment to open the view as shown.
Table 1.2 contains a view of other useful task management capabilities in Visual Studio .NET.
Table 1.2. Task List Management Tools from the Show Tasks Menu Item
Double-click an item in the Task List to move focus to that location in your code. Resolve the problem, remove or modify the comment to indicate that it has been resolved, and move on to the next task in the list.
The Task List categories are represented by an icon. You can check the help documentation for "Task List Views" for the list of icons. You will become accustomed to Task List icons as you use the Task List.
Built-in intelligence includes IntelliSense to figure out which tasks should be displayed as you move from context to context in the Visual Studio IDE. IntelliSense technology includes member lists, parameter information, quick info complete word, and automatic brace matching in the IDE. Choose Edit, IntelliSense to explicitly invoke IntelliSense features. (See the section "IntelliSense" later in this chapter for an overview of these features.)
From earlier versions of Basic, we inherited the ' and Rem comment tokens. To add a comment in Visual Basic .NET, simply precede some text in the code editor with either the apostrophe or the Rem token.
Many programmers comment out blocks of code that they have written for testing purposes, no longer need, or perhaps haven't quite finished but want ignored in order to compile. Visual Basic .NET includes the Comment Out Selected Lines and Uncomment the Selected Lines toolbuttons. Comment and Uncomment are available on the Text Editor toolbar or the Advanced submenu on the Edit menu.
To comment several lines of code, click and drag the mouse, highlighting all the code you want to comment. Click the Comment Out Selected Lines toolbutton. Each line in the selection should now have an apostrophe as the first character in the line.
It's probably okay to leave blocks of code commented out temporarily. An easy way of blocking out code and ensuring that it gets cleaned up eventually is to use a conditional compiler directive and a TODO comment task reminder. Listing 1.7 demonstrates the technique.
Listing 1.7 Using compiler conditional code to remove commented code
1: Private Sub Form1_Load(ByVal sender As System.Object, _ 2: ByVal e As System.EventArgs) Handles MyBase.Load 3: ' TODO: Demonstrates code removed by a compiler directive 4: ' that always evaluates to False 5: #If False Then 6: Dim I As Integer 7: For I = 1 To 100 8: Debug.WriteLine(I) 9: Next I 10: #End If 11: 12: End Sub
The #If False Then conditionally compiled code has a test that is always False, hence the code in lines 6 through 9 is effectively commented out. The TODO task will remind you to clean this code up if it remains commented out.
The Visual Studio IDE adds a couple of new editing features. From the General view, which you access by choosing Tools, Options, Text Editor, Basic, you can instruct the IDE to add line numbers in the left margin of the code editor and to automatically wrap text if it exceeds the virtual edge of the code editor page. See Figure 1.6 for a pictorial view of the Word Wrap option in the foreground; you can see the line numbers added in the background.
Figure 1.6. General text editor options include line numbering and word wrap features, turned on by making the selections shown here.
The presence of line numbers has no effect on the code or its compilation. Word wrap is automatic. If you resize the code editor, wrapped code and comments are adjusted accordingly . You don't need the remark token for wrapped comments; nor do you need the code continuation character, the underscore (_), for automatically wrapped code.
Wrapped code is indented on the first line but begins in column one on subsequent lines. This can make reading the wrapped text a bit difficult.