How to iterate through a sub-menu?

Is there a way to iterate though every member of a sub menu when the parent contains more than just the sub menu as its children?

For example, lets say I have the following “Recent File” menu item and it’s sub menu items:

mnuFileRecent
     mnuFileRecentSub(0)
     mnuFileRecentSub(1)
     mnuFileRecentSub(2)
     mnuFileRecentSub(3)
     mnuFileRecentBar
     mnuFileRecentClear

The mnuFileRecentSub array is built on the fly and will vary in size. I would like to iterate over every mnuFileRecentSub menu item, but there is no mnuFileRecentSub.Ubound method, mnuFileRecentSub.Count gives a “Item does not exist” error, and Ubound(mnuFileRecentSub) gives an “Incompatible parameters” error.

I can use the count of mnuFileRecent (which in the above case gives “6”) and just subtract 3, but that requires that the number of menu items after the array is constant, which in this case it is, but if I wanted to have another variable length menu below the first might not be the case.

Am I missing something?

Cheers.

-bill k

Menu arrays are not regular arrays (similar to control arrays, now called control sets). You have to keep track yourself of the number of elements. You can’t use Ubound, IndexOf, etc.

One possibility is to loop over the parent’s children and check for the separator. Somehow along this:

Dim isRecent As Boolean = True For i As Integer = 0 To mnuFileRecent.Count - 1 If mnuFileRecent.Item(i).Text = MenuItem.TextSeparator Then isRecent = False End If isRecent Then // mnuFileRecent.Item(i) is an element of the menu array Else // mnuFileRecent.Item(i) is the mnuFileRecentBar or the mnuFileRecentBar End Next

An alternative is to subclass MenuItem for the menu array, then you can do a check with IsA:

For i As Integer = 0 To mnuFileRecent.Count - 1 If mnuFileRecent.Item(i) IsA MyRecentMenuItemSubclass Then ... Else ... End Next

My approach is to always re-build the menu in EnableMenu in a MenuItem subclass:

[code]// mnuFileRecent is the MenuItem with Index = 0 and Visible = False (it acts like a template only)
// clear all array elements but not the invisible one with Index 0
Do Until mnuFileRecent.Item(mnuFileRecent.Count - 1) Is Self
mnuFileRecent.Remove(mnuFileRecent.Count - 1)
Loop

Dim RecentFiles() As FolderItem
If Not MenuRecentWasCleared Then // a variable set to True by the user clicking on mnuFileRecentClear
// Get your data for the recent menu items here (for example by querying the database)
For …
RecentFiles.Append(…
Next
End

For i As Integer = 0 To RecentFiles.Ubound
Dim menu As New MenuItem()
menu.Text = RecentFiles(i).DisplayName
menu.Tag = RecentFiles(i)
AddHandler menu.Action, AddressOf MenuAction
mnuFileRecent.Append(menu)
Next[/code]
… and create an action handler in this subclass:

Function MenuAction(item As MenuItem) As Boolean Dim fi As FolderItem = item.Tag ... Return True End Function

Thanks Eli, I think that sub-classing and rebuilding the menu in the Enable Menu’s event is clever, but I’ll stick to the brute force method of looking for the text separator. It would be much more convenient if there was some consistency in how these things (control sets, menu “arrays”, etc.) were implemented. Thanks for your suggestions.

Have you tried checking the count of the parent: mnuFileRecent.Count?

That’s how I’m doing it now Paul. But as you know, the count of the parent (mnuFileRecent.Count) also includes the additional menu items that in my case are not part of the recent file list (mnuFileRecentBar and mnuFileRecentClear). As long as the number of “additional” menu item is constant it’s a simple matter to avoid them in the iteration, but this isn’t particularly flexible.

For i = 0 to mnuFileRecent.Count - 3 
   'Do something with mnuFileRecentSub(i)
Next i

I actually only used a Recent Files menu as an example, since it’s something that most developers end up implementing. In my case I’m actually iterating through a menu of video input and output devices attached to the user’s computer and the menu is much more complex than the simple “Recent Files” example I gave initially.

I’ll probably just iterate through everything, checking the menu item’s “.Name” property to see if it is a member of the sub menu that I’m interested in (“mnuFileRecentSub” in the above example), but this seems unnecessarily tedious.

Store the final count somewhere so you can use it later.