Al margen de que el código no es óptimo, no hay nada ilegal en él...
El comentario (siguiente, el tachado) es erróneo (aparece el constructor de clase, que pasé por alto). No obstante, tras su declaración la función llamada lo creará si lo precisa, luego sobra hacerlo aquí y por tanto basta su declaración:
Dim submenu As ArrayList
(excepto que en esta línea declaraste un array de arraylist, y sobra como array, es decir elimina los paréntesis)
Dim submenu As New ArrayList()Lo que sucede es que posiblemente no entiendas el formulario MDI.
Un formulari MDI, siempre subsume el menú, del formulario hijo en su propio menú.
bueno siempre no... Esto está controlado por la propiedad AllowMerge del menustrip. (Abajo del todo, en la última sección, te pongo un ejemplo para dicho caso, son cambios ligeros)
Así cuando tú seleccionas Ventas, se crea el formulario con los menús asociados a él, y lo mismo con Compras... (o con alguno más si añadieras más), pero una vez que (por ejemplo) 'Ventas' tiene el foco, su menú se integra en el padre. A su vez el formulario hijo que pierde el foco (por ejemplo "Compras"), ve de vuelta su menú sobre sí, siendo retirado del formulario padre...
Una forma de verlo muy muy claro, es añadir el siguiente código al frmSubmenus
Haciendo que el formulario hijo ocupe toda el área cliente del formulario padre, no habría sitio para el menú del hijo...
Private Sub frmSubmenus_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
Me.WindowState = FormWindowState.Maximized
End Sub
Y eso es todo...
A continuación, lo que te presento es algunas correciones...
En VB, no hay "BREAK", para los bloques de control "select case", luego las sentencias 'Exit select', sobran si ya se llegó al final del código del propio 'case'.
Tampoco tiene sentido llamar al araylist 'submenú... conforme a la función simplemente genera una lista, luego no tiene sentido darle un nombre más propio que lista. Tampoco es necesario asignarlo Nothing, si luego lo vas a crear...
de hecho el 'case else' sobra, y se pone solo por lo molesto del 'warning'... aunque el propio compilador ya detectaría que como de entrada es nothing, eso es lo que devuelve y que por tanto el warning, es absurdo...
Public Function MenuSecundario(ByVal txt As String) As ArrayList
Dim lista As ArrayList
Select Case txt
Case "Ventas"
lista = New ArrayList
lista.Add("Cotizacion")
lista.Add("Pedidos")
lista.Add("Clientes")
lista.Add("por Autorizar")
lista.Add("Calendario")
lista.Add("Estadisticas")
Case "Compras"
lista = New ArrayList
lista.Add("Pendientes")
lista.Add("Administrador")
lista.Add("Productos")
lista.Add("Proveedores")
lista.Add("Clientes")
lista.Add("Calendario")
lista.Add("Estadisticas")
Case Else
lista = Nothing
End Select
Return lista
End Function
en el siguiente código hay 3 cosas que decir...
1- submenu es un objeto arraylist, la función llamada lo creará si lo precisa, luego sobra hacerlo aquí, basta su declaración.
2- El try...catch, carece de sentido, la línea "If Not IsNothing(submenu) Then" ya previene el posible error que pudiera ser generado, el recorrido de la lista como se hace con 'for each' no va a generar error', lo mismo que añadir ítems al menu... ahí el único error posible es que no existiera el menustrip1. Algo que se va a detectar en diseño, a poco que se pruebe el proyecto... luego poner try....catch, donde no son necesarios es una práctica lastrante.
3 - El msgbox, también sobra, aunque en diseño, para probar puedes ponerlo, de todas manearas unas décimas de segundo, después se podrá ver sobre la ventana MDI, luego...
Private Sub frmSubMenus_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
For Each ctr As Control In Me.Controls
Me.ToolTip1.SetToolTip(ctr, ctr.ToString)
Next
'Try
Dim submenu As ArrayList
submenu = MenuSecundario(Me.Text)
If Not IsNothing(submenu) Then
For Each str As String In submenu
'MsgBox(str)
MenuStrip1.Items.Add(str)
Next
End If
'Catch ex As Exception
'MsgBox("ERROR." + vbLf + ex.Message + vbLf + ex.ToString)
'End Try
End Sub
En esta sección, hemos movido la declaración del form al módulo de clase, fuera de la funcionalidad del evento.
El try...catch, también sobra, pero puedes mantenerlo mientras lo pruebas, antes de compilar, coméntal dichas líneas...
Lo más importante... como no has limitado de ninguna manera que pueda seguir creando más formularios 'Ventas, 'Compras'...cada vez que pulses en el menuStrip "Ventas", ó "Compras", generarás un nuevo formulario, cada uno con su propio menú, el problema es que no sabrás distinguir uno de otro...
Entonces o bien limitas a que solo se cree un único menú de cada tipo o bien 'personaliza el nombre' para cada uno...
La forma más simple de personalizar el nombre, es autonumerarlos... Es el código que añado sobre lo que tú tienes...
Dim form As frmSubmenus
Private Sub MenuStrip_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip.ItemClicked
Static childrens As Int16
Try
form = New frmSubmenus
form.MdiParent = Me
form.Text = e.ClickedItem.Text & "-" & childrens.ToString
form.Show()
childrens += 1
Catch ex As Exception
MsgBox("ERROR." + ex.Message)
End Try
End Sub
p.d.: añado los cambios para que cada formulario porte su propio menú... de forma independiente.
Ahora si tu prefieres que cada menú hijo tenga su propio menú sobre sí, y no subsumido en el 'padre', tienes que hacer estos cambios:
Ve a las propiedades del formulario MDI, selecciona el objeto MenuStrip1, cambia su propiedad
AllowMerge del menustrip1 a FALSE
Y ahora cambia el código en cada formulario según el code de cada uno que pongo a continuación...
Private Sub frmSubMenus_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Dim submenu As ArrayList
For Each ctr As Control In Me.Controls
Me.ToolTip1.SetToolTip(ctr, ctr.ToString)
Next
' Como ahora el texto de cada formulario está autonemuerado (pero comenzando con un guión)
' Tomamos la parte común del nombre...
' Esto tendría más fácil solución si en vez de pasar un string, se pasara un valor numérico
' por ejemplo: (1=Ventas, 2=compras, otro=else) partiendo quizás de una enumeración...
Dim strName As String
Dim k As Integer = InStr(Me.Text, "-")
If (k > 0) Then
strName = Me.Text.Substring(0, k - 1)
Else
strName = Me.Text
End If
submenu = MenuSecundario(strName)
If Not IsNothing(submenu) Then
For Each str As String In submenu
Me.MenuStrip1.Items.Add(str)
Next
End If
End Sub
El autonumerado sigue válido para el caso, así verás más ventanas del mismo tipo cada una con su propio menú... (esto es copia del código del último bloque antes de la linea de sección).
Dim form As frmSubmenus
Private Sub MenuStrip_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip.ItemClicked
Static childrens As Int16
Try
form = New frmSubmenus
form.MdiParent = Me
form.Text = e.ClickedItem.Text & "-" & childrens.ToString
form.Show()
childrens += 1
Catch ex As Exception
MsgBox("ERROR." + ex.Message)
End Try
End Sub
Y si tienes activado El windowSTate Maximized... tendrás otra línea de menú bajo el principal, prueba con y sin estas líneas...
Private Sub frmSubmenus_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
Me.WindowState = FormWindowState.Maximized
End Sub
Aún así, debrrías limitar la creación de formularios, no es tolerable que cada vez que se pulse el menú, se cree una nueva ventana, porque durante una sesión un mismo menú podría ser pulsado 50 veces, crear 50 formularios... seguramente no sea necesario, creo que es algo que dejas abierto y no es adecuado. Como mínimo habría que eliminar el formulario previo del mismo tipo...