RibbonX-Workshop - Dynamisches Menü

Dynamisches Menü - Teil 1

In diesem Teil lernen wir, wie man ein Menü mit dynamischen Inhalten füllen kann.

Zum Füllen des Menüs nutzen wir eine Tabelle mit dem Namen MenuDescript. Sie können das Menü so jederzeit erweitern. Sie können das Menü auch zur Laufzeit der Datei erweitern. Hierzu in die Tabelle eine Schaltfläche einfügen, der sie die Codezeile objRibbon.Invalidate zuweisen.

Natürlich können Sie das dynamicMenu auch als Untermenü in ein vorhandenes Menü einbauen, oder dem dynamicMenu auch ein normales Menü oder ein weiteres dynamicMenu hinzufügen.



RibbonX-Code:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="olLoad_DNM">
    <ribbon>
        <tabs>
            <tab id="tab0" label="DynamicMenu">
                <group id="grp0" label="Gruppe 1">
                   <dynamicMenu id="dmnu0" label="Sub Menu" getContent="GetContent_Menu1"/>
                 </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>


Inhalt der Tabelle:

DynamicMenu

VBA-Code:

Option Private Module
Option Explicit

Public objRibbon As IRibbonUI

Public Sub olLoad_DNM(ribbon As IRibbonUI)
Set objRibbon = ribbon
End Sub

Sub GetContent_Menu1(control As IRibbonControl, ByRef XMLString)
 
Dim lngInhalt       As Long
Dim strStartZeile   As String
Dim strInhalt       As String
Dim strEndZeile     As String
Dim xlLastCell      As Long
    
    
    With ThisWorkbook.Sheets("MenuDescript")
         
         xlLastCell = .Range("A" & Rows.Count).End(xlUp).Row
    
         strStartZeile = "<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
            
            For lngInhalt = 2 To xlLastCell
            
                strInhalt = strInhalt & _
                             "<button id=""" & .Range("A" & lngInhalt).Value & """" & _
                             " label=""" & .Range("B" & lngInhalt).Value & """" & _
                             " screentip=""" & .Range("D" & lngInhalt).Value & """" & _
                             " onAction=""" & .Range("C" & lngInhalt).Value & _
                             """/>"
            Next
     End With
     
        strEndZeile = strStartZeile & strInhalt & " </menu>"
        
        XMLString = strEndZeile
      
End Sub

Public Sub onAction_Button1(control As IRibbonControl)
       MsgBox "Element " & control.ID & " gedrückt", 64, "Hinweis"
End Sub



Dynamisches Menü - Teil 2

In Teil 1 haben wir gelernt wie man ein Menü mit dynamischen Inhalten füllen kann. In diesem Teil gehen wir ein klein wenig weiter. Wir fügen mehrere dynamische Menüs ein in die wir Dateinamen aus verschiendenen Ordnern einlesen. Diese Dateien können dann über das erstellte Menü geöffnet werden. Im Beispiel benutze zwei auf Laufwerk C gespeicherte und mit Excel-Dateien gefüllte Ordner. Der erste Ordner trägte den Namen AAA und der zweite Ordner den Namen BBA.

Erstellen Sie zuerst eine neue Datei. Bennen Sie eine Tabelle in Datei Übersicht. Alle anderen Blätter bitte löschen.

Gehen Sie nun in den VBE und fügen Sie ein neues Modul ein. In dieses Modul den folgenden Code. Dieser Code wird später die Ordner auslesen und die Dateinamen temporär in der Tabelle Datei Übersicht in Spalte A ablegen.

Private lngCount As Long
Private sPfad As String


Public Function DateienAuflisten(sPfad As String)

Dim i As Long

With Application
    .ScreenUpdating = False
    .DisplayAlerts = False
End With

lngCount = 0

SearchFiles sPfad, "*.xl*"
    
If lngCount = 0 Then
    MsgBox "Es wurde in der Ordnerstruktur" & sPfad & " keine Dateien gefunden!"
    Exit Function
End If
DateienAuflisten = strList


With ThisWorkbook.Worksheets("Datei Übersicht")
    .Range(.Cells(1, 1), .Cells(lngCount, 1)) = _
        WorksheetFunction.Transpose(strList)
End With

With Application
    .ScreenUpdating = False
    .DisplayAlerts = False
End With

End Function

Private Sub SearchFiles(strFolder As String, strFileName As String)
    Dim objFolder As Object
    Dim objFile As Object
    Dim objFSO As Object
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    For Each objFile In objFSO.GetFolder(strFolder).Files
        If objFile.Name Like strFileName Then
            Redim Preserve strList(0 To 1, lngCount)
            strList(0, lngCount) = objFile.Name
            strList(1, lngCount) = objFile.Path
            lngCount = lngCount + 1
        End If
    Next
    For Each objFolder In objFSO.GetFolder(strFolder).Subfolders
        SearchFiles strFolder & "\" & objFolder.Name, strFileName
    Next

End Sub


Fügen Sie nun ein weiteres Modul ein und in diesen den folgenden Code. Dieser Code wird die dynamicMenu später mit den Dateinamen füllen. Damit man aber die Dateiendungen nicht erscheint trennen wir diese per Code einfach ab.

(Anmerkung: Das onLoad-Ereignis über der Prozedur "GetContent_Menu1" muss stehen bleiben).
Option Private Module
Option Explicit

Public objRibbon As IRibbonUI

Public Sub olLoad_DNM(ribbon As IRibbonUI)
Set objRibbon = ribbon
End Sub

Sub GetContent_Menu1(control As IRibbonControl, ByRef XMLString)
 
Dim lngInhalt       As Long
Dim strStartZeile   As String
Dim strInhalt       As String
Dim strEndZeile     As String
Dim xlLastCell      As Long
Dim UOrdner         As String
Dim wbName          As String

Rem Ordnername 
UOrdner = Replace(control.Tag, "/", "\")

Rem Hauptordner & Ordner angeben 
ThisWorkbook.Worksheets("Datei Übersicht").Cells.ClearContents
DateienAuflisten (UOrdner)

Rem Prüfen ob Tabelle leer und aussteigen wenn leer 
If ThisWorkbook.Worksheets("Datei Übersicht").Range("A1").Value = "" Then Exit Sub

Rem Letzte beschriebene Zelle suchen 
xlLastCell = ThisWorkbook.Worksheets("Datei Übersicht").Range("A" & Rows.Count).End(xlUp).Row


    With tbMenuscript

         strStartZeile = "<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
            
            For lngInhalt = 1 To xlLastCell 'Letzte Zeile 1.00 
                wbName = Left(ThisWorkbook.Worksheets("Datei Übersicht").Range("A" & lngInhalt).Value, _
                         InStr(1, ThisWorkbook.Worksheets("Datei Übersicht").Range("A" & lngInhalt).Value, ".") - 1)
                         
                strInhalt = strInhalt & _
                             "<button id=""" & "btn" & lngInhalt & """" & _
                             " label=""" & wbName & """" & _
                             " screentip=""" & ThisWorkbook.Worksheets("Datei Übersicht").Range("A" & lngInhalt).Value & """" & _
                             " imageMso=""" & "FooterInsertGallery" & """" & _
                             " onAction=""" & "xlOpenFile" & """" & " tag=""" & UOrdner & ThisWorkbook.Worksheets("Datei Übersicht").Range("A" & lngInhalt).Value & _
                             """/>"
                             
            Next
     End With

        strEndZeile = strStartZeile & strInhalt & " </menu>"
        
        XMLString = strEndZeile
      
End Sub


Die folgende Prozedur in ein beliebiges (allgemeines) Modul einfügen. Diese Prozedur wird von den Schaltflächen im dynamischen Menü aufgerufen (die entsprechende Datei geöffnet).

Public Sub xlOpenFile(control As IRibbonControl)
   Workbooks.Open control.Tag
End Sub


Kommen wir nun zum RibbonX-Code. Im RibbonX-Code geben wir im TAG-Attribut den Pfad zu den Ordnern an. Da in RibbonX kein Backslash erlaubt ist müssen wir den einfachen Slash nutzen. Dieser Slash wird in der Prozedur wieder in einen Backslash umgewandelt. Sonderzeichen und Umlaute müssen maskiert werden (UNICODE).

Öffnen Sie die Datei mit dem CustomUI-Editor. In diese dann eine UI-Part einfügen und in diesen den folgenden Code.

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="olLoad_DNM">
  <ribbon>
     <tabs>
       <tab id="tab0" label="Ordner">
          <group id="grp0" label="Dateien">
               <menu id="mnu0" label="1.0" size="large" imageMso="_1">
                  <dynamicMenu id="dmnu01" label="Ordner 1" tag="C:/AAA/" getContent="GetContent_Menu1"/>
                  <dynamicMenu id="dmnu02" label="Ordner 2" tag="C:/BBA/" getContent="GetContent_Menu1"/>
               </menu>
          </group>
       </tab>
     </tabs>
  </ribbon>
</customUI>


Dynamisches Menü - Teil 3

Im dritten Teil fügen wir dem dynamischen Menü dynamische Untermenüs hinzu. Im Beispiel wird das Menü vier mal "verschachtelt".

Der RibbonX-Code entspricht dem aus Teil 2. Für jedes dynamische Untermenü gibt es eine eigene Tabelle und eine eigene Prozedur ("xl07_dynamicmenu_Teil 3" im Download "Download Dynamic-Menu").

Ein Beispielcode für ein dynamisches Menü mit einem dynamischen Untermenü.

Sub GetContent_Menu1(control As IRibbonControl, ByRef XMLString)
 
Dim lngInhalt       As Long
Dim strStartZeile   As String
Dim strInhalt       As String
Dim strEndZeile     As String
Dim xlLastCell      As Long
    
    
    With ThisWorkbook.Sheets("Untermenu_1")
         
         xlLastCell = .Range("A" & Rows.Count).End(xlUp).Row
    
         strStartZeile = "<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
            
            For lngInhalt = 2 To xlLastCell
            
                strInhalt = strInhalt & _
                             "<button id=""" & .Range("A" & lngInhalt).Value & """" & _
                             " label=""" & .Range("B" & lngInhalt).Value & """" & _
                             " screentip=""" & .Range("D" & lngInhalt).Value & """" & _
                             " onAction=""" & .Range("C" & lngInhalt).Value & _
                             """/>"
            Next
     End With
     
        strEndZeile = strStartZeile & "<dynamicMenu id=""dmnu4"" label=""Sub Menu 2"" imageMso=""_2"" getContent=""GetContent_Menu2"" />" & strInhalt & " </menu>"
        
        XMLString = strEndZeile
      
End Sub


Sub GetContent_Menu2(control As IRibbonControl, ByRef XMLString)
 
Dim lngInhalt       As Long
Dim strStartZeile   As String
Dim strInhalt       As String
Dim strEndZeile     As String
Dim xlLastCell      As Long
    
    
    With ThisWorkbook.Sheets("Untermenu_2")
         
         xlLastCell = .Range("A" & Rows.Count).End(xlUp).Row
    
         strStartZeile = "<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
            
            For lngInhalt = 2 To xlLastCell
            
                strInhalt = strInhalt & _
                             "<button id=""" & .Range("A" & lngInhalt).Value & """" & _
                             " label=""" & .Range("B" & lngInhalt).Value & """" & _
                             " screentip=""" & .Range("D" & lngInhalt).Value & """" & _
                             " onAction=""" & .Range("C" & lngInhalt).Value & _
                             """/>"
            Next
     End With
     
        strEndZeile = strStartZeile & strInhalt & " </menu>"
        
        XMLString = strEndZeile
      
End Sub



Dynamisches Menü - Teil 4

Der 4. Teil ist an Teil 3 angelehnt. Hier erstellen wir mehrere dynamische Untermenüs, die wiederum mehrere Untermenüs und Schaltflächen enthalten. Nutzen Sie dafür die Beispieldatei "xl07_dynamicmenu_Teil 4" im ZIP-Archiv "xl07_DynamicMenu". Da der Code nahezu identisch ist verzichte ich hier auf das Zeigen eines Beispielcodes.


Dynamisches Menü - Teil 5

Im fünften Teil erstellen wir ein dynamisches Menü mit Hilfe einer Konfigurationsdatei.

Kommen wir zunächst zum Aufbau der Konfigurationsdatei.
[Menü1Eintrag1]
isSeparator=0
separatorID=mnu1Separator
label=Eintrag 1
MacroName=onAction_Button
ButtonID=mnu1Button
imageMSO=FilesToolAddFiles
tag=Tag1
screentip=
supertip=
keytip=
getLabel=
getScreentip=
getSupertip=
getImage=

[Menü1Eintrag2]
isSeparator=0
separatorID=mnu1Separator
label=Eintrag 2
MacroName=onAction_Button
ButtonID=mnu1Button
imageMSO=FileInternetFax
tag=Tag2
screentip=
supertip=
keytip=
getLabel=
getScreentip=
getSupertip=
getImage=

[Menü1Eintrag3]
isSeparator=0
separatorID=mnu1Separator
label=Eintrag 3
MacroName=onAction_Button
ButtonID=mnu1Button
imageMSO=FontEmboss
tag=Tag3A;Tag3A2
screentip=
supertip=
keytip=
getLabel=
getScreentip=
getSupertip=
getImage=

[Menü1Eintrag4]
isSeparator=0
separatorID=mnu1Separator
label=Eintrag 4
MacroName=onAction_Button
ButtonID=mnu1Button
imageMSO=FontSizeDecrease
tag=Tag4
screentip=
supertip=
keytip=
getLabel=
getScreentip=
getSupertip=
getImage=


Beschreibung:
  1. In den Klammern tragen wir die Kennung für das Menü ein. Hier "Menü1Eintrag1", der Eintrag setz sich zusammen aus der "Menükennung" und dem Menüeintrag (Nummer). Das kann hilfreich sein wenn mehrere dynamische Menüs erstellt werden sollen.
  2. isSeparator = Soll bei dem Menüeintrag eine neue Gruppe beginnen setzen wir "isSeparator" auf 1.
  3. separatorID = Die ID für den Trennstrich. Die ID wird beim Zusammenstellen durch einen Zähler ergänzt. Dieses Attribut muss gefüllt sein wenn isSeparator auf 1 gesetzt ist..
  4. label = Hier geben wir an was auf der Schaltfläche stehen soll (Label). Dieses Attribut muss gefüllt sein. Nicht zusammen mit getLabel verwendbar.
  5. Macroname = Die auszuführende Prozedur geben wir hier an. Dieses Attribut muss gefüllt sein.
  6. ButtonID = Die ID für die Schaltfläche. Die ID wird beim Zusammenstellen durch einen Zähler ergänzt. Dieses Attribut muss gefüllt sein.
  7. imageMso = Das Icon welches die Schaltfläche bekommen soll. Die Namen bekommen Sie aus den bekannten Übersichten. Dieses Attribut darf leer sein.
  8. Tag = Das Tag-Attribut. Hier können Sie auch mehrere durch Semikolon getrennte Angaben machen. Dieses Attribut darf leer sein.
  9. screentip = Kurzbeschreibung (wird angezeigt beim draufzeigen). Dieses Attribut darf leer sein. Nicht zusammen mit getScreentip verwendbar.
  10. supertip = Langbeschreibung (wird angezeigt beim draufzeigen). Dieses Attribut darf leer sein. Nicht zusammen mit getSupertip verwendbar.
  11. keytip = Tastenkürzel. Maximal drei Zeichen. Nicht bereits verwendete Tastenkürzel nutzen. Dieses Attribut darf leer sein.
  12. getLabel = Variables Label (zur Laufzeit per Callback). Dieses Attribut darf leer sein. Nicht zusammen mit label verwendbar.
  13. getScreentip = Variabler Screentip (zur Laufzeit per Callback). Dieses Attribut darf leer sein. Nicht zusammen mit screentip verwendbar.
  14. getSupertip = Variabler Supertip (zur Laufzeit per Callback). Dieses Attribut darf leer sein. Nicht zusammen mit supertip verwendbar.
  15. getImage = Variables Icon (zur Laufzeit per Callback). Dieses Attribut darf leer sein. Nicht zusammen mit imageMso verwendbar.
Speichern Sie die Datei mit der Endung ini ab. Idealer Weise geben wir der Datei den selben Namen den die Officedatei trägt und legen sie im Pfad der Officedatei ab. Wichtig: Die Datei muss im ANSI-Format gespeichert werden.

Öffnen Sie nun Ihre Officedatei und wechseln Sie in dessen VBA-Projekt. Fügen Sie ein neues Modul ein und dort den folgenden Code. Wichtig: Bitte lassen Sie den Code möglichst unverändert.
Option Private Module
Option Explicit

Private Declare Function ReadXMLLayout Lib "kernel32.dll" Alias "GetPrivateProfileStringA" ( _
        ByVal MenueName As String, ByVal MenueAttribut As String, ByVal NullString As String, _
        ByVal LeerZeichen As String, ByVal Groesse As Long, ByVal INIPfad As String) As Long


Private Const MAX_COUNT = 255

 Public Function MenueinhaltEinlesen(varMenueName As Variant, varMenueAttribut As Variant, varINIPfad As Variant) As String

     Dim lngInhalt  As Long
     Dim strReturn  As String

     strReturn = Space$(MAX_COUNT)

     lngInhalt = ReadXMLLayout(varMenueName, varMenueAttribut, vbNullString, strReturn, MAX_COUNT, varINIPfad)

     MenueinhaltEinlesen = Left$(strReturn, lngInhalt)

 End Function
 
 Public Function ErstelleMenueInhalt(strConfigPath As String, strMenuPoint As String, lngFrom As Long, lngTo As Long) As String
 
  Dim lngConfKeyCount As Long
  Dim lngMenuPos      As Long
  Dim varXMLParams    As Variant
  Dim varConfKeyName  As Variant
  Dim varXMLParamsPos As Variant
  Dim varConfKeys     As Variant
  Dim varSepCount     As Variant
  
  varConfKeyName = Split("separatorID isSeparator ButtonId MacroName tag imageMSO label screentip supertip keytip getImage getLabel getScreentip getSupertip")
  varXMLParams = Split("<menuSeparator id_isSeparator_<button id_onAction_tag_imageMso_label_screentip_supertip_keytip_getImage_getLabel_getScreentip_getSupertip", "_")
  
  For lngMenuPos = lngFrom To lngTo
      varXMLParamsPos = varXMLParams
      For lngConfKeyCount = 0 To UBound(varXMLParamsPos)
         varConfKeys = MenueinhaltEinlesen(strMenuPoint & lngMenuPos, varConfKeyName(lngConfKeyCount), strConfigPath)
         If lngConfKeyCount = 1 Then
              If varConfKeys <> "1" Then varXMLParamsPos(0) = ""
              varConfKeys = ""
         End If
         If varConfKeys <> "" Then varXMLParamsPos(lngConfKeyCount) = varXMLParamsPos(lngConfKeyCount) & "=""" & _
                                   varConfKeys & IIf(lngConfKeyCount < 3, lngMenuPos, "") & IIf(lngConfKeyCount = 0, """/>", """")
      Next lngConfKeyCount
      For lngConfKeyCount = UBound(varXMLParamsPos) - 3 To UBound(varXMLParamsPos)
          If InStr(varXMLParamsPos(lngConfKeyCount), "=") Then varXMLParamsPos(lngConfKeyCount - 5) = ""
      Next lngConfKeyCount
      ErstelleMenueInhalt = ErstelleMenueInhalt & Join(Filter(varXMLParamsPos, "=")) & "/>"
  Next lngMenuPos
         
End Function

  1. Die Funktion ErstelleMenueInhalt erstellt den XML-Code für das dynamische Menü. Diese Funktion berücksichtigt automatisch sich gegenseitig ausschließende Attribute. Sollten Sie z.B. versehentlich label und getLabel in der Konfigurationsdatei füllen wird nur getLabel berücksichtig und label ignoriert.
  2. Die Funktion MenueinhaltEinlesen liest die Parameter aus der Konfigurationsdatei aus und übergibt sie an die Funktion ErstelleMenueInhalt


Fügen Sie nun ein weiteres Modul für die Rückruffunktionen (Callbacks) der Standardeinträge ein.
Option Private Module
Option Explicit

Public Sub onAction_Button(Optional control As IRibbonControl)
  MsgBox "Es wurde die Schaltfläche mit der ID " & control.ID & " gedrückt." & vbCrLf & vbCrLf & _
         "Das Tag-Attribut enthält den Eintrag:" & vbCrLf & control.Tag, 64, control.ID
End Sub

Fügen Sie nun ein weiteres Modul ein. In dieses legen wir die Rückruffunktion für das dynamische Menü.
Option Private Module
Option Explicit


Public objRibbon As IRibbonUI

Public Sub olLoad_DNM(ribbon As IRibbonUI)
Set objRibbon = ribbon
End Sub

Sub GetContent_Menu1(control As IRibbonControl, ByRef XMLString)
 
'########   Beginn Deklarationen ######
   Dim strConfPath      As String
   Dim strStartZeile    As String
   Dim strInhalt        As String
   Dim strEndZeile      As String
'########   Ende Deklarationen ######


'########   Konfigurationsdatei ######
      strConfPath = ThisDocument.Path & "\" & Left(ThisDocument.Name, InStr(1, ThisDocument.Name, ".") - 1) & ".ini"
   
'########   Startzeile erstellen ######
      strStartZeile = "<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
            
'########   Menü setzen ######
      strInhalt = ErstelleMenueInhalt(strConfPath, "Menü1Eintrag", 1, 4)

'########   Endzeile erstellen ######
      strEndZeile = strStartZeile & strInhalt & " </menu>"

'########   XML-String zurückgeben ######
      XMLString = strEndZeile


End Sub
  1. In der Zeile Konfigurationsdatei wird der Pfad zur Konfigurationsdatei angegeben. Im Beispiel befindet sie sich im Pfad der Worddatei und trägt den Namen der Worddatei.
  2. In der Zeile Menü setzen übergeben wir den Pfad, das gewünschte Menü (hier Menü1) mit den Zusatz "Eintrag" (ohne die Nummer die in der Konfiguration hinter "Eintrag" steht) und Start und Ziel der Menüeinträge (wenn Sie wie im Beispiel 4 Einträge haben geben Sie 1 als Start und 4 als Ziel ein) an die Funktion ErstelleMenueInhalt welche uns den XML-Code für den Menüinhalt zurückgibt.


Speichern und schließen Sie die Officedatei und öffnen Sie sie im Custom-UI-Editor. Fügen Sie das Office 2010 Office UI Part ein (für Office 2007 das entsprechende Office-UI-Part mit Anpassung des Namespaces) und dorthinein den XML-Code.
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
 <ribbon>
   <tabs>
     <tab idMso="TabHome">
       <group id="grp0" label="Menü1" insertBeforeMso="GroupClipboard">

         <dynamicMenu id="dmnu0" screentip="Menütest" imageMso="CreateSiteWorkflow" size="large" getContent="GetContent_Menu1"/>
         <separator id="spr2" />
         <button id="btn0" screentip="Schaltfläche 1" tag="Tag1" imageMso="FilePrint" size="normal" onAction="onAction_Button" />
         <button id="btn1" screentip="Schaltfläche 2" tag="Tag2A1;Tag2A2;Tag2A3" imageMso="FilePrintQuick" size="normal" onAction="onAction_Button" />
         <button id="btn2" screentip="Schaltfläche 3" tag="Tag3" imageMso="FilePermission" size="normal" onAction="onAction_Button" />
         <button id="btn3" screentip="Schaltfläche 4" tag="Tag4" imageMso="PictureColorMenu" size="normal" onAction="onAction_Button" />
         <button id="btn4" screentip="Schaltfläche 5" tag="Tag5A1;Tag5A2" imageMso="PictureRemovePicture" size="normal" onAction="onAction_Button" />
         <button id="btn5" screentip="Schaltfläche 6" tag="Tag6" imageMso="PictureBackgroundRemovalMarkForeground" size="normal" onAction="onAction_Button" />
         <button id="btn6" screentip="Schaltfläche 7" tag="Tag7" imageMso="PictureBackgroundRemovalMarkBackground" size="normal" onAction="onAction_Button" />

	</group>
     </tab>
   </tabs>
 </ribbon>
</customUI>

Natürlich können Sie auch hier Menüs kaskadieren. Auch dafür finden Sie Beispiele im ZIP-Arciv "xl07_DynamicMenu", dort im Ordner "wd_dynamicmenu_Teil 5". Beispiele herunterladen