Professional VB 2005 with .NET 3.0 (Programmer to Programmer)

A form is just a special kind of class in Windows Forms. A class becomes a form based on inheritance. A form must have the System.Windows.Forms class in its inheritance tree, which causes the form to have the behavior and object interface a form requires.

The previous section on changes in Windows Forms 2.0 mentioned that forms can be used by referring to a default instance. However, the preferred technique is to treat a form like any other class, which means creating an instance of the form and using the instance. Typical code would look like this:

Dim f As New Form1 f.Show()

There is one circumstance in which loading a form the same way as a class instance yields undesirable results. Let’s cover that next.

Showing Forms via Sub Main

When a form is instanced via the technique just described, it is referenced by an object variable, which establishes an object reference to the instance. References are covered in detail in Chapter 2.

References can go away as object variables go out of scope or are set to other references or to Nothing. When all object references to a form are gone, the form is disposed of and therefore vanishes. This is particularly apparent if you want to start your application with a Sub Main, and then show your first form inside Sub Main. You might think this would work:

' This code will not work in VB 2005!! Sub Main() ' Do start up work here ' After start up work finished, show the main form... Dim f As New Form1 f.Show() End Sub

What happens if you try this, however, is that Form1 briefly appears and then immediately vanishes, and the application quits. That’s because the object variable $f$ went out of scope, and it was the only reference to the form that was shown. Therefore, the form was destroyed because it had no references pointing to it.

To get around this behavior, you could use the default instance as the startup form, but there’s a better way that stays within good object-oriented conventions. Replace the line that shows the form, as shown in the following code:

' This code will work fine in VB 2005 Sub Main() ' Do start up work here Dim f As New Form1 Application.Run(f) End Sub

Now Sub Main will transfer control to the form, and the form won’t vanish when Sub Main ends.

Setting the Startup Form

Instead of using Sub Main as your application entry point, you can also define a startup form, which is the form that will be loaded first when your application begins. To define the startup form, you need to open the Properties dialog box for the project and set the Startup form setting. Do this using the Project Properties menu. You can also invoke the window by right-clicking the project name in Solution Explorer and selecting Properties from the context menu. The Properties dialog for a Windows application is shown in Figure 15-1.

Figure 15-1

If the Properties menu item doesn’t appear under your Project menu, open the Solution Explorer (Ctrl+Alt+L), highlight the project name (it will be in bold font), and then try again.

Startup Location

Often, you’ll want a form to be centered on the screen when it first appears. VB.NET does this automatically for you when you set the StartPosition property. The following table shows the settings and their meanings:

Open table as spreadsheet

StartPosition Value

Effect

Manual

Show the form positioned at the values defined by the form’s Location property

CenterScreen

Show the form centered on the screen

WindowsDefaultLocation

Show the form at the window’s default location

WindowsDefaultBounds

Show the form at the window’s default location, with the window’s default bounding size

CenterParent

Show the form centered in its owner

Form Borders

Forms have a number of border options in Windows Forms. The FormBorderStyle property is used to set the border option, and the options can affect the way a form can be manipulated by the user. The options available for FormBorderStyle include the following:

Each of these has a different effect on the buttons that appear in the title bar of the form. For details, check the help topic for the FormBorderStyle property.

Always on Top - The TopMost Property

Some forms need to remain visible at all times, even when they do not have the focus. Examples are floating toolbars and tutorial windows. In Windows Forms, forms have a property called TopMost. Set it to True to have a form overlay other forms even when it does not have the focus.

Note that a form with TopMost set to True is on top of all applications, not just the hosting application. If you need a form to only be on top of other forms in the application, this capability is provided by an owned form.

Owned Forms

As with the TopMost property, an owned form floats above the application, but it does not interfere with using the application. An example is a search-and-replace box. However, an owned form is not on top of all forms, just the form that is its owner.

When a form is owned by another form, it is minimized and closed with the owner form. Owned forms are never displayed behind their owner form, but they do not prevent their owner form from gaining the focus and being used. However, if you want to click on the area covered by an owned form, the owned form has to be moved out of the way first.

A form can only have one “owner” at a time. If a form that is already owned by Form1 is added to the owned forms collection for Form2, then the form is no longer owned by Form1.

There are two ways to make a form owned by another form. It can be done in the owner form or in the owned form.

AddOwnedForm() Method

In the owner form, another form can be made owned with the AddOwnedForm() method. Here is code to make an instance of Form2 become owned by Form1. This code would reside somewhere in Form1 and would typically be placed just before the line that shows the instance of Form2 to the screen:

Dim frm As New Form2 Me.AddOwnedForm(frm)

Owner Property

The relationship can also be set up in the owned form. This is done with the Owner property of the form. Here is a method that would work inside Form2 to make it owned by a form that is passed in as an argument to the function:

Public Sub MakeMeOwned(frmOwner As Form) Me.Owner = frmOwner End Sub

Because this technique requires a reference to the owner inside the owned form, it is not used as often as using the AddOwnedForm() method in the Owner form.

OwnedForms Collection

The owner form can access its collection of owned forms with the OwnedForms property. Here is code to loop through the forms owned by a form:

Dim frmOwnedForm As Form For Each frmOwnedForm In Me.OwnedForms Console.WriteLine(frmOwnedForm.Text) Next

The owner form can remove an owned form with the RemoveOwnedForm property. This could be done in a loop like the previous one, with code like the following:

Dim frmOwnedForm As Form For Each frmOwnedForm In Me.OwnedForms Console.WriteLine(frmOwnedForm.Text) Me.RemoveOwnedForm(frmOwnedForm) Next

This loop would cause an owner form to stop owning all of its slaved forms. Note that those deslaved forms would not be unloaded, they would simply no longer be owned.

Making Forms Transparent and Translucent

Windows Forms offers advanced capabilities to make forms translucent, or parts of a form transparent. You can even change the entire shape of a form.

The Opacity Property

The Opacity property measures how opaque or transparent a form is. A value of 0 percent makes the form fully transparent. A value of 100 percent makes the form fully visible. Any value greater than 0 and less than 100 makes the form partially visible, as if it were a ghost. Note that an opacity value of 0 percent disables the capability to click the form.

Very low levels of opacity, in the range of 1 or 2 percent, make the form effectively invisible, but still allow the form to be clickable. This means that the Opacity property has the potential to create mischievous applications that sit in front of other applications and “steal” their mouse clicks and other events.

Tip 

Percentage values are used to set the opacity in the Properties window. However, if you want to set the Opacity property in code, you must use values between 0 and 1 instead, with 0 being equivalent to 0 percent and 1 being equivalent to 100 percent.

Tool and dialog windows that should not completely obscure their background are one example of a usage for Opacity. Setting expiration for a “free trial” by gradually fading out the application’s user interface is another.

The following block of code shows how to fade a form out and back in when the user clicks a button named Button1. You may have to adjust the Step value of the array, depending on your computer’s performance:

Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click Dim i As Double For i = -1 To 1 Step 0.005 ' Note - opacity is a value from 0.0 to 1.0 in code ' Absolute value is used to keep us in that range Me.Opacity = System.Math.Abs(i) Me.Refresh Next i End Sub

The TransparencyKey Property

Instead of making an entire form translucent or transparent, the TransparencyKey property enables you to specify a color that will become transparent on the form. This enables you to make some sections of a form transparent, while other sections are unchanged.

For example, if TransparencyKey is set to a red color and some areas of the form are that exact shade of red, then they will be transparent. Whatever is behind the form shows through in those areas; and if you click in one of those areas, you are actually clicking the object behind the form.

TransparencyKey can be used to create irregularly shaped “skin” forms. A form can have its BackgroundImage property set with an image, and by just painting a part of the image with the TransparencyKey color, you can make parts of the form disappear.

The Region Property

Another way to gain the capability of “skins” is by using the Region property of a form. The Region property allows a shape for a form to be encoded as a “graphics path,” thereby changing the shape from the default rectangle to another shape. A path can contain line segments between points, curves and arcs, and outlines of letters, in any combination.

The following example changes the shape of a form to an arrow. Create a new Windows application. Set the FormBorderStyle property of Form1 to None. Then place the following code in the Load event for Form1:

Dim PointArray(6) As Point PointArray(0) = New Point(0, 40) PointArray(1) = New Point(200, 40) PointArray(2) = New Point(200, 0) PointArray(3) = New Point(250, 100) PointArray(4) = New Point(200, 200) PointArray(5) = New Point(200, 160) PointArray(6) = New Point(0, 160) Dim myGraphicsPath As _ System.Drawing.Drawing2D.GraphicsPath = _ New System.Drawing.Drawing2D.GraphicsPath myGraphicsPath.AddPolygon(PointArray) Me.Region = New Region(myGraphicsPath)

When the program is run, Form1 will appear in the shape of a right-pointing arrow. If you lay out the points in the array, you will see that they have become the vertices of the arrow.

Visual Inheritance

By inheriting from System.Windows.Forms.Form, any class automatically gets all the properties, methods, and events that a form based on Windows Forms is supposed to have. However, a class does not have to inherit directly from the System.Windows.Forms.Form class to become a Windows form. It can become a form by inheriting from another form, which itself inherits from System.Windows.Forms .Form. In this way, controls originally placed on one form can be directly inherited by a second form. Not only is the design of the original form inherited, but also any code associated with these controls (the processing logic behind an Add New button, for example). This means that you can create a base form with processing logic required in a number of forms, and then create other forms that inherit the base controls and functionality.

VB 2005 provides an Inheritance Picker tool to aid in this process. Note, however, that a form must be compiled into either an .exe or .dll file before it can be used by the Inheritance Picker. Once that is done, the addition of a form that inherits from another form in the project can be achieved by selecting Project Add Windows Form and then choosing the template type of Inherited Form in the resulting dialog.

Scrollable Forms

Some applications need fields that will fit on a single screen. While you could split the data entry into multiple screens, an alternative is a scrollable form.

You can set your forms to automatically have scrollbars when they are sized smaller than the child controls they contain. To do that, set the AutoScroll property of your form to True. When you run your program, resize the form to make it smaller than the controls require and presto - instant scrolling.

Important 

You cannot have both Autoscroll and IsMdiContainer set to True at the same time. MDI containers have their own scrolling functionality. If you set Autoscroll to True for an MDI container, the IsMdiContainer property will be set to False, and the form will therefore cease to be an MDI container.

MDI Forms

MDI (Multiple Document Interface) forms are forms that are created to hold other forms. The MDI form is often referred to as the parent, and the forms displayed within the MDI parent are often called children. Figure 15-2 shows a typical MDI parent with several children displayed within it.

Figure 15-2

Creating an MDI Parent Form

In Windows Forms, a regular form is converted to an MDI parent form by setting the IsMDIContainer property of the form to True. This is normally done in the Properties window at design time.

A form can also be made into an MDI parent at runtime by setting the IsMDIContainer property to True in code. However, the design of an MDI form is usually rather different from that of a normal form, so this approach is not often needed.

Differences in MDI Parent Forms between VB6 and VB 2005

In VB6, an MDI parent form can only contain controls that have a property called Align, which is similar to the Dock property in Windows Forms. These controls, such as a PictureBox, can then contain other controls.

In Windows Forms, an MDI parent can contain any control that a regular form can contain. Buttons, labels, and the like can be placed directly on the MDI surface. Such controls will appear in front of any MDI child forms that are displayed in the MDI client area.

It is still possible to use controls such as PictureBoxes to hold other controls on a Windows Forms MDI parent. These controls can be docked to the side of the MDI form with the Dock property, which is discussed in the section “Dynamic Sizing and Positioning of Controls.”

MDI Child Forms

In Windows Forms, a form becomes an MDI child at runtime by setting the form’s MDIParent property to point to an MDI parent form. This makes it possible to use a form as either a standalone form or an MDI child in different circumstances. In fact, the MDIParent property cannot be set at design time - it must be set at runtime to make a form an MDI child. (Note that this is completely different from VB6, where it was necessary to make a form an MDI child at design time.)

Any number of MDI child forms can be displayed in the MDI parent client area. The currently active child form can be determined with the ActiveForm property of the MDI parent form.

An MDI Example in VB 2005

To see these changes to MDI forms in action, you can do the following step-by-step exercise. It shows the basics of creating an MDI parent and making it display an MDI child form:

  1. Create a new Windows application. It will have an empty form named Form1. Change both the name of the form and the form’s Text property to MDIParentForm.

  2. In the Properties window, set the IsMDIContainer property for MDIParentForm to True. This designates the form as an MDI container for child windows. (Setting this property also causes the form to have a different default background color.)

  3. From the Toolbox, drag a MenuStrip control to the form. Create a top-level menu item called File with submenu items called New MDI Child and Quit. Also create a top-level menu item called Window. The File New MDI Child menu option will create and show new MDI child forms at runtime, and the Window menu will keep track of the open MDI child windows.

  4. In the Component Tray at the bottom of the form, click the MenuStrip item and select Properties. In the Properties window, set the MDIWindowListItem property to WindowToolStripMenuItem. This enables the Window menu to maintain a list of open MDI child windows, with a check mark next to the active child window.

  5. Create an MDI child form to use as a template for multiple instances. To do so, select Project Add Windows Form and click the Add button in the Add New Item dialog box. That will result in a new blank form named Form2. Place any controls you like on the form. As an alternative, you can reuse any of the forms created in previous exercises in this chapter.

  6. Now go back to MDIParentForm. In the menu editing bar, double-click the New MDI Child option under File. The Code Editor will appear, with the cursor in the event routine for that menu option. Place the following code in the event:

    Protected Sub NewMdiChildToolStripMenuItem _Click(ByVal sender As Object, ByVal e As System.EventArgs) ' This line may change if you are using a form with a different name. Dim NewMDIChild As New Form2() 'Set the Parent Form of the Child window. NewMDIChild.MDIParent = Me 'Display the new form. NewMDIChild.Show() End Sub

  7. In the menu editing bar for MDIParentForm, double-click the Quit option under File. The Code Editor will appear, with the cursor in the event routine for that menu option. Place the following code in the event:

    Protected Sub QuitToolStripMenuItem_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) End End Sub

  8. Now run and test the program. Use the File New MDI Child option to create several child forms. Note how the Window menu option automatically lists them with the active one checked and allows you to activate a different one.

Arranging Child Windows

MDI parent forms have a method called LayoutMDI that will automatically arrange child forms in the familiar cascade or tile layout. For the preceding example, add a menu item to your Windows menu called Tile Vertical and insert the following code into the menu item’s Click event to handle it:

Me.LayoutMdi(MDILayout.TileVertical)

To see an example of the rearrangement, suppose that the MDI form in Figure 15-2 is rearranged with the MDILayout.TileVertical option. It would then look similar to the image in Figure 15-3.

Figure 15-3

Dialog Forms

In VB6 and earlier, forms were shown with the Show method, and this technique is still used in Windows Forms. In both VB6 and VB 2005, the Show method by default displays modeless forms, which are forms that allow the user to click off them onto another form in the application.

Applications also sometimes need forms that retain control until their operation is finished. That is, you can’t click off such a form onto another form. Such a form is called a modal form.

In VB6, showing a modal form required using a special parameter on the Show method. Showing a form modally is done differently in Windows Forms, with the ShowDialog() method. Here is code for showing a modal dialog in Windows Forms:

Dim frmDialogForm As New DialogForm frmDialogForm.ShowDialog()

DialogResult

It is common when showing a dialog form to need to get information about what action the user selected. This was often done with a custom property in VB6, but Windows Forms has a built-in property for that purpose. When a form is shown with the ShowDialog() method, the form has a property called DialogResult to indicate its state.

The DialogResult property can take the following enumerated results:

When the DialogResult property is set, the dialog is hidden as a byproduct. That is, setting the DialogResult property causes an implicit call to the Hide method of the dialog form, so that control is released back to the form that called the dialog.

The DialogResult property of a dialog box can be set in two ways. The most common way is to associate a DialogResult value with a button. Then, when the button is pressed, the associated value is automatically placed in the DialogResult property of the form.

To set the DialogResult value associated with a button, the DialogResult property of the button is used. If this property is set for the button, it is unnecessary to set the DialogResult in code when the button is pressed. Here is an example that uses this technique.

In Visual Studio 2005, start a new VB Windows application. On the automatic blank form that comes up (named Form1), place a single button and set its Text property to Dialog.

Now add a new Windows Form by selecting Project Add Windows Form and name it DialogForm.vb. Place two buttons on DialogForm and set the following properties for the buttons:

Open table as spreadsheet

Property

Value for First Button

Value for Second Button

Name

OKButton

CancelButton

Text

OK

Cancel

DialogResult

OK

Cancel

Do not put any code in DialogForm at all. The form should look like the one shown in Figure 15-4.

Figure 15-4

On the first form, Form1, place the following code in the Click event for Button1:

Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Dim frmDialogForm As New DialogForm() frmDialogForm.ShowDialog() ' You're back from the dialog - check user action. Select Case frmDialogForm.DialogResult Case DialogResult.OK MsgBox("The user pressed OK") Case DialogResult.Cancel MsgBox("The user pressed cancel") End Select frmDialogForm = Nothing End Sub

Run and test the code. When a button is pressed on the dialog form, a message box should be displayed (by the calling form) indicating the button that was pressed.

The second way to set the DialogResult property of the form is in code. In a Button_Click event, or anywhere else in the dialog form, a line like the following can be used to set the DialogResult property for the form and simultaneously hide the dialog form, returning control to the calling form:

Me.DialogResult = DialogResult.Ignore

This particular line sets the dialog result to DialogResult.Ignore, but setting the dialog result to any of the permitted values also hides the dialog form.

Forms at Runtime

The life cycle of a form is like that of all objects. It is created and later destroyed. Forms have a visual component, so they use system resources, such as handles. These are created and destroyed at interim stages within the lifetime of the form. Forms can be created and will hold state as a class, but will not appear until they are activated. Likewise, closing a form doesn’t destroy its state.

The following table summarizes the states of a form’s existence, how you get the form to that state, the events that occur when the form enters a state, and a brief description of each:

Open table as spreadsheet

Code

Events

Fired Description

MyForm = New Form1

Load

The form’s New() method will be called (as will InitializeComponent).

MyForm.Show() or

HandleCreated

Use Show() for modeless display.

MyForm.ShowDialog()

Load

Use ShowDialog() for modal display.

VisibleChanged

The HandleCreated event only fires the first time the form is shown or after it has previously been closed.

Activated

MyForm.Activate()

Activated

A form can be activated when it is visible but does not have the focus.

MyForm.Hide()

Deactivate

Hides the form (sets the Visible property to False)

VisibleChanged

MyForm.Close()

Deactivate

Closes the form and calls Dispose to release the window’s resources

Closing

During the Closing event, you can set the CancelEventArgs.Cancel property to True to abort the close.

Closed

VisibleChanged

HandleDestroyed

Also called when the user closes the form using the control box or X button

Disposed

The Deactivate event will only fire if the form is currently active.

Note: There is no longer an Unload event. Use the Closing or Closed event instead.

MyForm.Dispose()

None

Use the Close() method to finish using your form.

MyForm = Nothing

None

Releasing the reference to the form flags it for garbage collection. The garbage collector calls the form’s Finalize() method.

Категории