WinForms from Scratch


A typical Windows Forms application has at least one form. Without the form it's just an "application," which is pretty boring. A form is simply a window, the unit of the Microsoft user interface we've seen since Windows 1.0.

One form in a WinForms application is typically the main form , which means that it is either the parent or the owner [1] of all other forms that may be shown during the lifetime of the application. It's where the main menu is shown, along with the toolbar, status bar, and so on. When the main form goes away, the application exits.

[1] The distinction between a form's "parent" and "owner" is covered in detail in Chapter 2: Forms.

The main form of an application can be a simple message box, a dialog box, a Single Document Interface (SDI) window, a Multiple Document Interface (MDI) window, or something more complicated, such as the forms you're used to seeing in applications like Visual Studio .NET. These latter forms may include multiple child windows, tool windows, and floating toolbars .

If your application is enormously simple, you can implement it using the staple of any windowing system, the lowly message box :

 
 Public Class MyFirstApp   Shared Sub Main()       System.Windows.Forms.MessageBox.Show("Hello, Windows Forms")   End Sub End Class 

If you're new to Visual Basic .NET, Main is the entry point for any Visual Basic .NET application. The Main function must be a member of a class, and hence the need for MyFirstApp. At runtime, the Common Language Runtime (CLR) identifies the class that implements the Main function and calls that class. However, no instance of the MyFirstApp class is created by the .NET runtime when our code is loaded and executed, so our Main function must be marked Shared, which marks a method as available without creating an instance of the type.

The single line of real code in our first WinForms application calls the shared Show method of the System.Windows.Forms.MessageBox class, which is really a long-winded way of saying we're calling a method on the MessageBox class contained in the System.Windows.Forms namespace. Namespaces are used extensively in the .NET Framework Class Libraries (FCL) to separate types, such as classes, structures, enumerations, and so on, into logical groupings. This separation is necessary when you've got thousands of Microsoft employees working on the FCL as well as hundreds of third parties extending it and millions of programmers trying to learn it. Without namespaces, you need all kinds of wacky conventions to keep things uniquely named (as demonstrated by the existing Win32 API).

However, as necessary as namespaces are, they're a little too much typing for us, so we recommend the Visual Basic .NET Imports statement, as shown here:

 
  Imports System   Imports System.Windows.Forms  Public Class MyFirstApp   Shared Sub Main()       MessageBox.Show("Hello, Windows Forms")   End Sub End Class 

When the compiler sees that the MessageBox class is being used, it first looks in the global namespace , which is where all types end up that aren't contained by a namespace (for example, the MyFirstApp class is in the global namespace). If the compiler can't find the type in the global namespace, it looks at all the namespaces currently being used ”in this case, System and System.Windows.Forms. If the compiler finds a type name being used that exists in two or more namespaces, it produces an error and we're forced to go back to the long notation. But in practice this is rare enough to make the short form the form of choice when you're typing code by hand.

However, even though the MessageBox class is enormously handy for showing your users simple string information or asking them yes/no questions, it's hard to build a real application with MessageBox. For most things, you'll need an instance of the Form class (or a Form-derived class):

 
 Public Class MyFirstApp   Shared Sub Main()       Dim myform As Form = New Form()       myform.Show() ' Not what you want to do   End Sub End Class 

Although this code will show the form, you'll have to be quick to see it because Show shows the form modelessly. If you're not steeped in user interface lore, a modeless form is one that displays but allows other activities (called modes ) to take place. So, immediately after Show puts our new form on the screen, it returns control to the Main function, which promptly returns, exiting the process and taking our nascent form with it. To show a form modally ” that is, to not return control to the Main function until the form has closed ”the documentation suggests using the ShowDialog function:

 
 Public Class MyFirstApp   Shared Sub Main()       Dim myform As Form = New Form()       myform.ShowDialog() ' Still not what you want to do   End Sub End Class 

This code would show a blank form and wait for the user to close it before returning control to the Main function, but it's not the code you will generally be writing. Instead, to make it accessible in other parts of your application, you'll be designating one form as the main form. To do this, pass the main form as an argument to the Run method of the Application object, which also resides in the System.Windows.Forms namespace:

 
 Imports System.Windows.Forms Public Class MyFirstApp   Shared Sub Main()       Dim myform As Form = New Form()       Application.Run(myform) ' This is what you want to do   End Sub End Class 

The Application class's static Run method will show the main form, and when it's closed, Run will return, letting our Main function exit and closing the process. To see this in action, you can compile your first WinForms application using the following command line: [2]

[2] To get a command prompt with the proper PATH environment variable set to access the .NET command line tools, click on Start, then Programs, then Microsoft Visual Studio .NET, then Visual Studio .NET Tools, then Visual Studio .NET Command Prompt. If you don't have VS.NET installed, you can set up the PATH using the corvars.bat batch file in your FrameworkSDK\Bin directory.

 
 C:\> vbc /target:winexe MyFirstApp.vb /reference:System.Windows.Forms.dll 

This command invokes the compiler on our source file, asking it to produce a Windows application via the /target:winexe flag and bringing in the System.Windows.Forms.dll library for a definition of the types we're using. You should note that the Imports statement merely saves us typing. Without the reference to System.Windows.Forms.dll, the compiler would complain that it could not find the System.Windows.Forms namespace. Common practice is to match namespace names to the names of their assemblies, but that's not required.

Now that that the compiler has produced MyFirstApp.exe, you can execute it and see an application so boring, it's not even worth a screen shot. When you close the form, MyFirstApp.exe will exit, ending your first WinForms experience.

To spice things up a bit, we can set a property on our new form before showing it:

 
 Public Class MyFirstApp   Shared Sub Main()       Dim myform As Form = New Form()       myform.Text = "Hello, WinForms!"       Application.Run(myform)   End Sub End Class 

Like most objects in the FCL, Form objects have several properties to access, methods to call, and events to handle. In this case, we've set the Text property, which, for a form, sets the caption. We could do the same thing to set other properties on the form, showing it when we were finished, but that's not the way we generally do things in WinForms. Instead, each custom form is a class that derives from Form and initializes its own properties:

 
 Public Class MyFirstForm   Inherits Form   Public Sub New()       Me.Text = "Hello, WinForms!"   End Sub End Class Public Class MyFirstApp   Shared Sub Main()       Dim myform As Form = New MyFirstForm()       Application.Run(myform)   End Sub End Class 

Notice that the MyFirstForm class Inherits the Form class. This is the Visual Basic .NET syntax for implementation inheritance, a powerful tool for object-oriented programmers that is new to Visual Basic. Previous versions of Visual Basic have supported a technique called interface inheritance . Implementation inheritance allows a class (in this case, MyFirstForm) not only to act as an instance of the Form class but also to have access to all the Public, Protected, and Friend members of Form. This includes data fields, properties, and methods. Inheritance is both powerful and complex; try Object Oriented Design , by Peter Coad and Edward Yourdon, for more information on this and other Object Oriented (OO) topics.

Still, our form is pretty boring. It doesn't even include a way to interact with it except for the system-provided adornments. We can add some interactivity by adding a button:

 
 Public Class MyFirstForm     Inherits Form     Public Sub New()         Me.Text = "Hello, WinForms!"  Dim button As Button = New Button()   button.Text = "Click me!"   Me.Controls.Add(button)  End Sub End Class 

Adding a button to the form is a matter of creating a new Button object, setting the properties that we like, and adding the Button object to the list of controls that the form manages . This code will produce a button on the form that does that nifty 3-D depress thing that buttons do when you press them, but nothing else interesting will happen. That's because we're still not handling the button's Click event , where an event is a way for a control to notify its container that something has happened . For example, the following code handles the button's Click event:

 
 Public Class MyFirstForm     Inherits Form  Private WithEvents button As Button  Public Sub New()         Me.Text = "Hello, WinForms!"         button = New Button()         button.Text = "Click me!"         Me.Controls.Add(button)     End Sub  Sub button_Click(sender As Object, e As EventArgs) _   Handles button.Click   MessageBox.Show("That's a strong, confident click you have")   End Sub  End Class 

Handling the button's Click event involves two things. First, we declare a private class-level variable of type Button using the WithEvents keyword. This notifies the compiler that other members in the class will wish to interact with the events that the Button class may fire. Notice that the variable is initialized in the constructor.

The second thing that's needed is an implementation of the event handler with the appropriate signature. Typically, these events use a standard naming convention of <variable name>_<Event name>, in this case, button_Click. The signature of almost all .NET events is a procedure that takes two parameters: an object that represents the sender of the event (our button, in this case), and an instance of a System.EventArgs object (or an object that derives from the EventArgs class).

Notice than the button_Click procedure is decorated with a new keyword, Handles. This construct determines which actual event the procedure is tied to ”in this case, button.Click. Declaring an event-handling procedure requires several new keywords and careful programming to align the right handler with the right event. Luckily, it's also unnecessary because of the WinForms Wizard and the WinForms Designer provided by Visual Studio .NET.



Windows Forms Programming in Visual Basic .NET
Windows Forms Programming in Visual Basic .NET
ISBN: 0321125193
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net