You want a form to be in the center of the display when it first appears.
Solution
Set the form’s StartPosition property to CenterScreen.
Discussion
That was easy, but there may be cases where you need to set this property to Manual, but you still want the form to appear centered sometimes. To accomplish this, add the following code to theLoadevent handler for your form:
You want to display a form without any of the typical window border elements. Also, you want the user to be able to move the window around by clicking and dragging a PictureBoxcontrol.
Solution
Sample code folder: Chapter 04\MoveBorderlessForm
Turning off the border elements is easy:set the form’sFormBorderStyleproperty to None. Then you can manage the drawing of the form elements yourself.
Creating a fake titlebar that moves the form is a little more involved. Create a new Windows Forms application, and add two controls: aButtoncontrol namedActCloseand aPictureBox control namedDragBar. Change the button’sTextproperty toClose. Change the picture box’sBackColorproperty toActiveCaption, one of the system colors. Also, change the form’sFormBorderStyle property toNone. The form should look something like Figure 4-17.
Figure 4-17. A borderless form with a pretend titlebar
Now, add the following source code to the form’s code template:
Const HT_CAPTION As Integer = &H2 Const WM_NCLBUTTONDOWN As Integer = &HA1
Private Sub DragBar_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles DragBar.MouseDown ' ----- When the user clicks the left mouse button, act ' as if the user actually clicked on the form's ' title bar. If (e.Button = Windows.Forms.MouseButtons.Left) Then ' ----- Don't hold on to the mouse locally. DragBar.Capture = False
' ----- Trick the form into thinking it received a ' title click. Me.WndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, _ CType(HT_CAPTION, IntPtr), IntPtr.Zero)) End If End Sub
Private Sub ActClose_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ActClose.Click Me.Close() End Sub
Run the program, and drag the colored picture box control to move the form around the display.
Discussion
All of the activity within a Windows form happens through messages being processed through a Windows procedure, or WndProc. This method has existed since the introduction of Windows. The .NET Framework put a bunch of pretty classes around the messy parts of this messaging system, but it’s still there, and you can interact with it to suit your needs.
Normally, when you left-click on a form window (or a control, which is just a different type of window), aWM_LBUTTONDOWNmessage is passed to the relevant Windows procedure. That message ultimately triggers a call to one of your form’sMouseDownevent handlers.
Your application includes a “message pump” that makes calls to each form’sWndProcprocedure for message processing. But there is nothing to stop you from calling that procedure yourself. In fact, it’s exposed as a form class member.
When theDragBar picture box control receives the mouse down event, it says, “Hey, I’ll just send a fake message to my window’sWndProcroutine so that it thinks the user clicked on the titlebar.” And that’s what the code does. It sends aWM_NCLBUTTONDOWNmessage to the form. The “NCL” part of that code means “Non-Client,” the area that contains the titlebar and borders. The HT_CAPTION flag tells the message that the click occurred in the caption area (the titlebar). This is all that’s needed to trick the form.
Use the form’sOpacityproperty to slowly fade it out. Create a new Windows Forms application, and add aButtoncontrol namedActCloseto the form. Change the button’sTextproperty toClose. Then add the following source code to the form’s code template:
Private Sub ActClose_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles ActClose.Click ' ----- Fade out the form. Dim counter As Integer
For counter = 90 To 10 Step -20 Me.Opacity = counter / 100 Me.Refresh() Threading.Thread.Sleep(50) Next counter
Me.Close() End Sub
Run the program, and click on theClosebutton to see the form fade away.
Discussion
You’ll find that on some systems, the form momentarily blinks to black right when it makes the transition from an opacity of 1.0 to any other opacity value. On such systems, setting the Opacity property to a non-1.0 value during the Loadevent handler still causes a blink, but it does so when the form first opens, not during the cool fadeout.
Private Sub AboutProgram_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' ----- Prepare the form for later fade-out. Me.Opacity = 0.99 End Sub
Use the form’sTransparencyKeyproperty to identify a color that will be invisible. The sample code in this recipe uses fuchsia for its “invisible color,” but you can choose any color that meets your display requirements.
Create a new Windows Forms application. ChangeForm1’sFormBorderStyleproperty toNone, itsStartPositionproperty toCenterScreen, and itsTransparencyKeyproperty toFuchsia. Then add the following source code to the form’s code template:
Private Sub Form1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Click ' ----- Any click closes the form. Me.Close() End Sub
Private Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles Me.Paint ' ----- Draw a nice logo form. e.Graphics.Clear(Color.Fuchsia) e.Graphics.FillRectangle(Brushes.Gold, 0.0F, _ Me.ClientRectangle.Height / 3.0F, _ CSng(Me.ClientRectangle.Width), _ Me.ClientRectangle.Height / 3.0F) e.Graphics.FillPolygon(Brushes.Gold, New PointF() { _ New Point(Me.ClientRectangle.Width / 4, 0), _ New Point (Me.ClientRectangle.Width / 2, _ Me.ClientRectangle.Height / 2), _ New Point(Me.ClientRectangle.Width / 4, _ Me.ClientRectangle.Height), _ New Point(0, Me.ClientRectangle.Height / 2)}) Dim largerFont = New Font(Me.Font.Name, 20) e.Graphics.DrawString("My Nice Program", _ largerFont, Brushes.Black, 20, _ (Me.ClientRectangle.Height / 2) - _ (largerFont.Height / 2)) End Sub
When you run the program, it appears similar to the display in Figure 4-18. (We left the development environment behind the form so that you could see the invisibility.)
Figure 4-18. A Form with transparent portions
Discussion
The initial release of Visual Basic 2005 included a bug that prevented the transparency color from properly appearing as transparent in some cases. Specifically, if your form included an image that contained the transparency color, and the workstation was using more than 24 bits of color for its display, the image appeared as opaque. To get around this problem, you need to set transparency on the image manually before you draw it:
Private Sub Form1_Paint(ByVal sender As Object,_ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles Me.Paint ' ----- This code assumes that the form's ' TransparencyKey property is "Fuchsia". Dim logoImage As Bitmap = Bitmap.FromFile( _ "C:\MyLogo.bmp") logoImage.MakeTransparent(Color.Fuchsia) e.Graphics.DrawImage(logoImage, 0, 0) End Sub
The Microsoft Knowledge Base number for this article is 822495.
See Also
Recipe 9.10 discusses invisibility colors and the TransparencyKey property in more detail.
You want to customize the menu structure in your main form at runtime. The structure should be based on settings made available by some user-configurable method.
Solution
Sample code folder: Chapter 04\RuntimeMenus
The menu-specific classes included in the Windows Forms library can be created at either design time or runtime. This recipe’s code adds a basic menu to a form at design time and enhances it at runtime by adding the user’s Internet Explorer “Favorites” to one of the menus.
Create a new Windows Forms application, and add aMenuStripcontrol namedMainMenuto the form. Perform the following actions on this menu:
Add a top-level menu namedMenuFile, using&Filefor itsTextproperty.
Add a top-level menu namedMenuFavorites, usingFa&voritesfor itsTextproperty.
Add a menu item namedMenuExitProgramthat is subordinate toMenuFile, usingE&xitfor itsTextproperty. Set itsShortcutKeysproperty toAlt+F4.
Add a menu item namedMenuNoFavoritesthat is subordinate toMenuFavorites, using(empty)for itsTextproperty. Set itsEnabledproperty toFalse.
Figure 4-19 shows a partial look at this form’s menu structure in design mode.
Figure 4-19. The initial menus for the runtime menu sample
Next, replace the form’s code template with the following code. I’ve highlighted the lines that do the actual adding of menu items:
Imports MVB = Microsoft.VisualBasic
Public Class Form1 Private Declare Auto Function GetPrivateProfileString_ Lib "kernel32" _ (ByVal AppName As String, _ ByVal KeyName As String, _ ByVal DefaultValue As String, _ ByVal ReturnedString As System.Text.StringBuilder, _ ByVal BufferSize As Integer, _ ByVal FileName As String) As Integer
Private Sub MenuExitProgram_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MenuExitProgram.Click ' ----- Exit the program. Me.Close() End Sub
Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' ----- Scan through the user's "Favorites" and ' add them as menu items. Dim favoritesPath As String
' ----- Determine the location of the "Favorites" ' folder. favoritesPath = Environment.GetFolderPath( _ Environment.SpecialFolder.Favorites) If (favoritesPath = "") Then Return If (My.Computer.FileSystem.DirectoryExists( _ favoritesPath) = False) Then Return
' ----- Call the recursive routine that builds the menu. BuildFavorites(MenuFavorites, favoritesPath)
' ----- If favorites were added, hide the ' "no favorites" item. If (MenuFavorites.DropDownItems.Count > 1) Then _ MenuNoFavorites.Visible = False End Sub
Private Sub BuildFavorites(ByVal whichMenu As _ ToolStripMenuItem, ByVal fromPath As String) ' ----- Given a starting directory, add all files ' and directories in it to the specified menu. ' Recurse for suborindate directories. Dim oneEntry As String Dim menuEntry As ToolStripMenuItem Dim linkPath As String Dim displayName As String
' ----- Start with any directories. For Each oneEntry In My.Computer.FileSystem. _ GetDirectories(fromPath) ' ----- Create the parent menu, but don't ' attach it yet. menuEntry = New ToolStripMenuItem( _ My.Computer.FileSystem.GetName(oneEntry))
' ----- Recurse to build the sub-directory branch. BuildFavorites(menuEntry, oneEntry)
' ----- If that folder contained items, ' then attach it. If (menuEntry.DropDownItems.Count > 0) Then _ whichMenu.DropDownItems.Add(menuEntry) Next oneEntry
' ---- Next, build the actual file links. Only ' look at ".url" files. For Each oneEntry In My.Computer.FileSystem. _ GetFiles(fromPath, FileIO.SearchOption. _ SearchTopLevelOnly, "*.url") ' ----- Build a link based on this file. These ' files are old-style INI files. linkPath = GetINIEntry("InternetShortcut", _ "URL", oneEntry) If (linkPath <> "") Then ' ----- Found the link. Add it to the menu. displayName = My.Computer.FileSystem. _ GetName(oneEntry) displayName = MVB.Left(displayName, _ displayName.Length - 4) menuEntry = New ToolStripMenuItem(displayName) menuEntry.Tag = linkPath whichMenu.DropDownItems.Add(menuEntry)
' ----- Connect this entry to the event handler. AddHandler menuEntry.Click, _ AddressOf RunFavoritesLink End If Next oneEntry End Sub
Private Sub RunFavoritesLink( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) ' ----- Run the link. Dim whichMenu As ToolStripMenuItem
whichMenu = CType(sender, ToolStripMenuItem) Process.Start(whichMenu.Tag) End Sub
Private Function GetINIEntry(ByVal sectionName As String, _ ByVal keyName As String, _ ByVal whichFile As String) As String ' ----- Extract a value from an INI-style file. Dim resultLength As Integer Dim targetBuffer As New System.Text.StringBuilder(500)
whichFile) Return targetBuffer.ToString() End Function End Class
Run the program, and access its Favorites menu to browse and open the current user’s Internet Explorer favorites.
Discussion
The bulk of this recipe’s code deals with scanning through a directory structure and examining each file and subdirectory. Most of the files in the “Favorites” folder have a .url extension and contain data in an “INI file” format.
The last “URL=” line provides the link we need to enable favorites support in our program.
The important part of the program is the building of the menu structure. Each menu item attached to the form’s main menuMenuStrip control is a relatedToolStripMenuItemclass instance. These can be attached to the menu at any time through itsDropDownItemscollection. Each menu item in turn has its ownDropDownItemscollection that manages subordinate menu items.
To make each new menu item do something, as you add them, connect them to the previously writtenRunFavoritesLinkmethod:
You want to display a custom shortcut menu to users when they right-click on a form or one of its controls.
Solution
Sample code folder: Chapter 04\ShortcutMenus
Use theContextMenuStrip control to design a shortcut menu (also called a context or pop-up menu) that you can attach to the controls (or form) of your choice.
Create a new Windows Forms application, and add aContextMenuStripcontrol namedMainShortcutMenu to the form. When you select that control, it adds a temporary standard menu to the control that you can use to add new menu items (see Figure 4-20).
Figure 4-20. Shortcut menus in design mode
Add two menu items to this shortcut menu:
A menu item namedMenuHello, usingSay Hellofor itsText property
A menu item namedMenuGoodbye, usingSay Goodbyefor itsTextproperty
Select the form itself, and then change itsContextMenuStripproperty toMainShortcutMenu.
Now, add the following source code to the form’s code template:
Private Sub MenuHello_Click(ByVal sender As System.Object,_ ByVal e As System.EventArgs) Handles MenuHello.Click MsgBox("Hello") End Sub
Private Sub MenuGoodbye_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MenuGoodbye.Click MsgBox("Goodbye") End Sub
Run the program, and right-click on the form. The shortcut menu will present itself, as shown in Figure 4-21. Clicking on the items puts up a message box saying “Hello” or “Goodbye.”
Figure 4-21.The shortcut menu in use
Discussion
Each form and control includes a ContextMenuStrip property that you can assign to any ContextMenuStrip control included with your form. You can create as many shortcut menus as needed for your controls.
Some controls, such as theTextBoxcontrol, already include default shortcut menus. If you wish to enhance one of these menus, you will have to design your own menu from scratch and provide your own implementations for menu items previously found in that control’s shortcut menu.