December 22, 2014
Hot Topics:

New Windows Forms Capabilities in Visual Basic.Net

  • June 29, 2001
  • By Paul Kimmel
  • Send Email »
  • More Articles »

Tech Ed ended last Thursday, June 21st. Microsoft heralded its new implementation of Visual Studio.NET, the new C# (C-Sharp) programming language, and its continued commitment to the Visual Basic language.

On Tuesday, Bill Gates and Air Bixhorn demonstrated the revised donkey.bas game, originally written by Chairman Bill, in its new incarnation as donkey.net. (Donkey.net will be available for download from Microsoft at http://msdn.microsoft.com/vbasic/donkey.asp, purportedly sometime the week of June 25th.) There was stark contrast between the two games. Donkey.bas, implemented in QBasic used ANSI characters for simple shape drawing, and donkey.net demonstrated 3D graphics rendering, forced feedback game controls, shaped Windows Forms, and Web Services that implemented new characters, including Evil Bunny and Peg-leg Pirate.

In addition to the hysterical peg-leg pirate hopping up and down on a twenty foot screen and being run over by Chairman Bill, is the fact that all of the capabilities on display in the simple game were implemented with Visual Basic.NET. In this article, we will look at a couple of the new features supported by Windows Forms, including the new stay-on-top and Opacity capabilities implemented as properties.

Making a Form Stay On Top

Sometimes you want a modeless form to stay on top. An obvious means of bringing a form into the foreground is to show the form as a modal form, accomplished with the Form.ShowDialog method in VB.NET. But what if you want a form to stay on top in a modeless state? For example, you may have contrived a status that is tracking your application's progress in the background and keeping the displayed status in the foreground.

To make something stay on top in VB.NET, all you have to do is set the TopMost property to True and the form will stay in the zero z-order position, even if the TopMost form does not have the focus. Because using the property is so simple, the code listing demonstrates a context in which you might actually use a TopMost form.

When I am building software, I like to use a Debug tool that allows me to write a log file and have a view of what's going on while the program is running, a tracing mechanism if you will. This is convenient as you can run the program outside of the IDE and still have a practical log of what the application is doing; the technique described approximates using the EventLog, which is another good solution.

To demonstrate the TopMost property, we will assume that we have a requirement to have a debug view of our application, to be able to track what is happening behind the scenes. The sample application uses one form with a StatusBar. The StatusBar is used to track application status. The second form is the trace view, a form named DebugWindow. The DebugWindow is always in the foreground, so its TopMost property is set to True in the Properties window. (Figure 1 shows the application. Figure 2 shows the DebugWindow.)

Figure 1. An application.

Figure 2. A TopMost DebugWindow.

To simulate processing, each time the Broadcast Button is pressed the StatusBar is updated with the current date and time - simulating the deployed behavior of the application - and the right window (Figure 2) shows the Debug Window. Perhaps the Debug Window is only available during black-box testing to provide testers with a trace file. No matter what is happening on the main form (Form1), the DebugWindow form remains in the foreground.

To implement the trace view behavior, I defined an interface. The interface defines one method named OnListen. Every class that implements the interface must implement on listen. The second class is Broadcaster. Broadcaster is a Singleton, which means there is only one instance of the class. The Broadcaster keeps track of the listeners. Every class that implements the listener interface can be registered with the broadcaster. To send a message to all listeners, all any client needs to do is use the Broadcaster Singleton object and call the Broadcast method. To become a listener, all any client needs to do is implement the Listener interface and register with the Broadcaster as a Listener using the AddListener method. The complete code listing follows. Each portion of the listing is followed by a brief synopsis of the code.

Listing 1 demonstrates using an interface and the new TopMost property in VB.NET to implement a trace window.

Public Class Form1  Inherits System.Windows.Forms.Form  Implements IListener[ Windows Form Designer generated code ]  Private Sub OnListen(ByVal Text As String) Implements IListener.OnListen    StatusBar1.Text = Text  End Sub    Private Sub Button1_Click(ByVal sender As System.Object, _                            ByVal e As System.EventArgs) _                            Handles Button1.Click    Broadcaster.Broadcast(Now)  End Sub    Private Sub Form1_Load(ByVal sender As System.Object, _                         ByVal e As System.EventArgs) _                         Handles MyBase.Load    Broadcaster.AddListener(Me)    DebugWindow.ShowWindow()  End SubEnd Class

Form1 is a subclass from System.Windows.Forms.Form and implements the IListener interface. The Sub OnListen demonstrates how to implement interface methods in VB.NET. The line [ Windows Form Designer generated code ] represents the code outlining capability of Visual Studio.Net.

Public Class DebugWindow  Inherits System.Windows.Forms.Form  Implements IListener[ Windows Form Designer generated code ]  Shared Sub ShowWindow()     Dim Form As New DebugWindow()    Form.Show()  End Sub    Private Sub Add(ByVal Text As String)   TextBox1.Text = Text & vbCrLf & TextBox1.Text  End Sub  Private Sub OnListen(ByVal Text As String) _                           Implements IListener.OnListen     Add(Text)  End Sub      Private Sub DebugWindow_Load(ByVal sender As System.Object, _                                 ByVal e As System.EventArgs) _                                 Handles MyBase.Load    TextBox1.Text = vbNullString    Broadcaster.AddListener(Me)  End Sub    Protected Overrides Sub Finalize()    Broadcaster.RemoveListener(Me)    MyBase.Finalize()  End SubEnd Class

The DebugWindow form represents the trace window. If you were to expand the collapsed generated code you would find Me.TopMost = True in the InitializeComponent method. DebugWindow.vb also inherits from Form and implements IListener. The Shared method creates an instance of the Debug Window and shows the form. (This is a convenient technique to avoid writing the same code to create and show the form.) Form1 calls the DebugWindow.ShowWindow method in Form1's OnLoad event, but you could easily turn this feature on and off. When the OnListen method of DebugWindow is called by the Broadcaster, the text is added to the top of the Multiline textbox. When DebugWindow is Finalized, the form is removed from the list of Broadcast recipients.

Public Interface IListener  Sub OnListen(ByVal Text As String)End Interface  Public Class BroadcasterClass  Private FListeners As New Collection()  Sub Broadcast(ByVal Text As String)    Dim Listener As IListener    For Each Listener In FListeners      Listener.OnListen(Text)    Next  End Sub  Sub AddListener(ByVal Listener As IListener)    FListeners.Add(Listener)  End Sub    Sub RemoveListener(ByVal Listener As IListener)    Dim I As Integer    For I = 1 To FListeners.Count      If (FListeners(I).Equals(Listener)) Then        FListeners.Remove(I)        Exit For      End If    Next  End SubEnd ClassPublic Module Factory  Public Function Broadcaster() As BroadcasterClass    Static FBroadcaster As BroadcasterClass    If (FBroadcaster Is Nothing) Then      FBroadcaster = New BroadcasterClass()    End If    Return FBroadcaster  End FunctionEnd Module

The Listener.vb file actually contains three elements: the IListener interface, the BroadcasterClass class, and the Factory module that creates only one instance of a Broadcaster on demand. IListener declares only one method, OnListen. All IListeners must implement OnListen. The Factory module declares a Static BroadcasterClass. The first time the Broadcaster function is called, FBroadcaster is Nothing and the object is created; on each subsequent call, the local, Static object is returned. The BroadcasterClass defines three methods: AddListener, RemoveListener, and Broadcast, as well as a Collection of Listeners. When an object implements IListener, all it has to do to receive messages is to call Broadcaster.AddListener(Me), passing a reference to self to the AddListener method. To stop listening, the Listener simply calls Broadcaster.RemoveListener(Me). Each time any code calls Broadcaster.Broadcast(string), every Listener is notified of the broadcast message.

Using an interface to define a broadcaster and listeners allows you to write more loosely coupled code. Notice that none of the listeners is referring to a specific object, neither are any of the listeners referring to any of the controls on those objects. You could devise a listener that updated a database, or use some new control to display status on the main form. In both cases, you would not have to change any of the existing code between the forms and broadcaster.

An alternate scenario for using TopMost is to create a Splash screen. If you show a Splash screen as a modal dialog, then your splash screen has to perform initialization of your application. But such a use for a splash screen is counterintuitive. With the TopMost property, you can display the splash form as a modeless form and initialize your application using some other, more appropriate object.

Using Opacity to Create Form Affects

The Opacity property of a Form works very simply. If Opacity is 0, then the object, usually a form, is transparent. If the Opacity is 1, representing 100% or Opaque, then the form is not transparent. You might use the Opacity property to fade in a splash form. Each tick of a timer control will increase the Opacity of the splash form until it is 100%. (Unfortunately, I cannot show you the form fading in. Using Alt+Print Screen shows the form as 100% opaque and Collage Complete was unable to capture the form until it was Opaque.)

The code sample is quite straightforward. Add an enabled timer to the Splash form and have the timer increase the Opacity until it is greater than or equal to 100%

Private Sub Timer1_Tick(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles Timer1.Tick    Opacity += 0.02    If (Opacity >= 1) Then Close()  End Sub

Alternatively you could use a Thread and have the thread increase the Opacity a little and sleep a little until the Opacity is 100%. The Threaded version follows.

Public Sub FadeIn()  While (Opacity < 1)    Opacity += 0.02    Sleep(175)    Text = "Thread: " & Opacity  End WhileEnd Sub

To create and use the Threaded version, create an instance of a Thread and pass it the Address of the FadeIn method as follows.

Dim Splash As New FormSplash()Splash.Opacity = 0Dim Thread As New Threading.Thread(AddressOf Splash.FadeIn)Splash.Show()Thread.Start()

The listing creates a Thread passing the AddressOf SplashForm.FadeIn. The form is shown, and the thread is started.

Finally, at Tech Ed, Microsoft presenters stated that Windows Forms are not Thread-safe. I am still experimenting with Threads and forms. The multithreaded version of the fade-in form seems to work okay, but further experimentation and information might be necessary to determine how reliable code like the preceding will work in VB.NET. In the meantime, the Timer version seems to work reasonably well.

About the Author

Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. He is the founder of Software Conceptions, Inc, founded in 1990. Kimmel performs contract software development services in North America and can be contacted at pkimmel@softconcepts.com






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel