ProblemYou 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. SolutionSample 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 a MenuStrip control named MainMenu to the form. Perform the following actions on this menu:
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 sampleNext, 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) resultLength = GetPrivateProfileString(sectionName, _ keyName, "", targetBuffer, targetBuffer.Capacity, _ 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. DiscussionThe 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. Here's a sample link to a popular search engine: [DEFAULT] BASEURL=http://www.google.com/ [InternetShortcut] URL=http://www.google.com/ 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 menu MenuStrip control is a related ToolStripMenuItem class instance. These can be attached to the menu at any time through its DropDownItems collection. Each menu item in turn has its own DropDownItems collection that manages subordinate menu items. To make each new menu item do something, as you add them, connect them to the previously written RunFavoritesLink method: AddHandler menuEntry.Click, AddressOf RunFavoritesLink |