1. Computing
Managing Forms - VB .NET Style
VB .NET gives you a lot of flexibility in managing forms

Much of this article is based on Chapter 5 of Matthew MacDonald's excellent book, User Interfaces in VB .NET. MacDonald does an excellent job of sketching out both a strategy and a technical overview showing how to handle multiple forms in a VB .NET application.

But I had several problems using MacDonald's book. This article is both a standalone explanation of some of the techniques Chapter 5 and it also expands and clarifies several of the things in the chapter that are incomplete.

One of the more cool tricks that you can do with VB.NET forms is explained in the short section, Forms With Holes near the end of the chapter. As McDonald explains it ...

You can define a special color for the form that will automatically be cut out by setting the form's TransparencyKey property. For example, if you choose dark blue, all occurrences of dark blue in your form become invisible. This includes occurences of the color in an image, a control, or even the form's background. In fact, these holes aren't just invisible -- you can even click through them to activate a program underneath!

The Visual Basic Help system says the same thing ...

Any mouse actions, such as the click of the mouse, that are performed on the transparent areas of the form will be transferred to the windows below the transparent area.

To try out this idea, and to have an example form for the rest of this article, I created a starting form (Form1) for our application with me, peeking out from the About Visual Basic web page behind it. This sample form is part of the system that can be downloaded at the end of the article.

Main Form

To see the form full size, click here.

This form is pretty cool ... except for one thing. The promised ability to "click through" to the form underneath doesn't work! I found the reason why in a newsgroup message.

The new graphics engine in Windows Forms, called GDI+, is a layer on top of Windows and not part of Windows itself. The TransparencyKey feature is built into Windows itself, and for it to work you must render with GDI, not with GDI+. ... GDI+, for performance reasons, will attempt to map a graphics call to GDI if the results would be the same.

(Thanks to Brian Pepin (Microsoft) for this clue.)

So, because the "hole" in the graphic was created with offline graphics editor and not rendered with GDI, mouse clicks don't get passed through the tranparent part of the form. If TransparentKey is set to Red in Form1, then this code will create a square 50 pixel "click through" area that works:

Dim myBrush As Brush = Brushes.Red
e.Graphics.FillRectangle(myBrush, 30, 30, 50, 50)

Hmmmm ... the Microsoft documentation doesn't say a thing about that!

Even though GDI+ is the successor to Windows Graphics Device Interface (GDI), the graphics device interface included with earlier versions of Windows and GDI+ optimizes many of the capabilities of GDI and provides additional features, it appears that not all of the bugs are worked out yet.

The main thrust of the chapter, however, is about how to manage multiple forms using a VB .NET Public class that creates a reference to all the forms that need to be managed in an application.

As MacDonald explains,

Things become a little trickier if you need to allow interaction between forms. For example, if you want to configure a control on one form using the code inside another form, you need to make sure you create and retain the required form variable, so it's available when you need it.

Much of the code needed to make this work was 'left as an exercise for the reader' because there were only code fragments available to demonstrate how to do it. Since it wasn't exactly clear to me, I thought it might not be clear to others. So I created some actual code to implement MacDonald's text. All this code is downloadable at the end of this article.

To start the demo application, I also used the form with the transparent cutout shown above. The other forms that we're going to use are these:

Forms

One of the main problems in managing multiple forms is that you can't access their properties. For example, if I try to simply Hide the main form Form1 in the code for myUserForm1, I get this set of available properties and methods for Form1:

Methods

Notice that Hide isn't one of them.

The best way to access these forms throughout an application is to create a class and make them shared objects in the class.

Public Class myFormLibrary
    Public Shared Form1 As Form
    Public Shared myUserForm1 As Form
    Public Shared myUserForm2 As Form
End Class

Simply declaring the objects, however, doesn't do the whole job. You also have to establish references to each of the objects. The easiest way to do this is to create those references when the form is loaded.

Private Sub Form1_Load( _
	ByVal sender As System.Object, _
	ByVal e As System.EventArgs) _
	Handles MyBase.Load
    myFormLibrary.Form1 = Me
End Sub

Once this is done, each form can be referenced 'at will' from anywhere in the system. For example, myUserForm1 has a button that hides the main form. Coding it is simplicity itself:

Private Sub Button1_Click( _
	ByVal sender As Object, _
	ByVal e As System.EventArgs) _
	Handles Button1.Click
    myFormLibrary.Form1.Hide()
End Sub

Another problem in managing forms is that if you only use the technical trick of making all the forms available, you can end up with a sort of 'spaghetti code' of form references. For example, suppose I want to change a property of one from from the code in another form (say ... BackgroundImage). I can code the change directly now:

myFormLibrary.myUserForm1.BackgroundImage = _
	Image.FromFile("")
Change the Background Image

But, suppose the file path of the graphic changes. Or perhaps there are a number of places in your code where you want to change this property. And what about checking for problems? For example, maybe the form you want to change has been closed. Stopping these things from garbaging up your code was what OOP was invented to solve in the first place. To keep this from being a problem here, MacDonald recommends managing the code through interfaces that you create in your application. In this application, I created a custom class that will change the background in any form passed to it.

Public Class ChangeForms
    Public Shared Sub ChangeImage( _
	ByVal frm As System.Windows.Forms.Form)
        If frm Is Nothing Then
            MsgBox("The form is not loaded.")
            Exit Sub
        End If
        frm.BackgroundImage = _
		Image.FromFile("")
    End Sub
End Class

The entire system is downloadable HERE . You will need to update the file path to a graphic of your choosing before it will run.

  1. About.com
  2. Computing
  3. Visual Basic

©2013 About.com. All rights reserved.