Click here to Skip to main content
15,881,833 members
Articles / Programming Languages / XML

VB.NET-XML based Dynamic Menu Component using Recursion Technique

Rate me:
Please Sign up or sign in to vote.
4.33/5 (6 votes)
15 Jan 20074 min read 81.9K   969   37   10
Generating Dynamic Menus (using recursion) in VB.NET using XML data

Introduction

In this article, we will see how to generate Dynamic Menus (using recursion) in VB.NET based on the XML data which has the complete details about the Menu like Menu Caption and the corresponding Event it has to trigger whenever the user clicks a Menu Item, etc. It's a generalized re-usable component written in such a way that it can be easily plugged to any application based on the requirement.

The main objective of this component is to generate Menus at runtime based on the values present in the XML Configuration file. Let's first have a look at the XML Configuration File assuming the File Name as Menu.xml and sample contents are as follows:

XML
<root>
<TopLevelMenu id="&amp;File">
       <MenuItem id = "New" OnClick="_New"/>
       <MenuItem id = "Open"/>
       <MenuItem id = "Send To">
              <MenuItem id ="Mail"/>
              <MenuItem id ="My Documents"/>
       </MenuItem>
</TopLevelMenu>
<TopLevelMenu id="&amp;Edit">
       <MenuItem id = "Copy"/>
       <MenuItem id = "Paste" OnClick="_Paste"/>
       <MenuItem id = "Clear">
             <MenuItem id = "F&amp;ormats"/>
              <MenuItem id ="Contents">
                    <MenuItem id = "Test" OnClick="_Test"/>
               </MenuItem>
       </MenuItem>
</TopLevelMenu>
</root>

From the above XML, it's evident that Nodes defined as TopLevelMenu will be the Parent/Top level Menu and the Nodes defined as MenuItem will be the corresponding child for it. Menu Captions are defined in the attribute named "id", you can manipulate the XML file to display custom Captions for Menu Items.

  • File - is the Top Level Menu
  • New - is the child of File
  • Open - is the child of File
  • SendTo - is the child of File
  • Mail - is the child of SendTo
  • My Documents - is the child of SendTo
  • Edit - is the Top Level Menu
  • Copy - is the child of Edit
  • Paste - is the child of Edit
  • Clear - is the child of Edit
  • Formats - is the child of Clear
  • Contents - is the child of Clear
  • Test - is the child of Contents

Note: The "&amp;" text facilitates the use of short-cut keys for menu items that are being defined.

OnClick - This is a main attribute which defines the Event the particular menu item should trigger whenever the user performs a click. For example, the New Menu Item has OnClick attribute defined as below:

XML
<MenuItem id = "New" OnClick="_New"/>

It means that VB.NET Form in which the Menu is getting displayed should have the below code pasted in:

VB.NET
Private Sub MenuItemOnClick_New(ByVal sender As Object, _
                                ByVal e As System.EventArgs)
    MessageBox.Show("New Clicked")
End Sub

Please note that Event Name is framed based on the below format.

MenuItemOnClick - is the hard-coded value in the component, it doesn't come from your XML File.

_New - is as defined in the OnClick Attribute. If you change the _New to _NewItem (let's say), then your Form Event should also be changed to:

VB.NET
Private Sub MenuItemOnClick_NewItem(ByVal sender As Object, _
                                    ByVal e As System.EventArgs
    MessageBox.Show("New Clicked")
End Sub

The dynamic menu component exposes Event Handlers for each and every Menu Item you have created with an attribute value of "OnClick". If you dont want to create an Event handler for a menu item, then you need not specify the OnClick attribute for it in the XML file.

Now let us now see the code details of the component which generates Menu dynamically based on the XML content.

DynamicMenu.vb

VB.NET
Public Class DynamicMenu

    ''''''''''''''''''''''variable declarations begins''''''''''''''''''''''
    'Create a main menu object.
    Private mainMenu As New mainMenu()
    'Object for loading XML File
    Private objXML As Xml.XmlDocument
    ' Create menu item objects.
    Private mItem As New MenuItem()
    'Menu handle that should be returned
    Private objMenu As Menu
    'Path of the XML Menu Configuration File 
    Public XMLMenuFile As String
    'Form Object in which Menu has to be build
    Public objForm As Object
    ''''''''''''''''''''''variable declarations ends '''''''''''''''''''''''

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'This method will get invoked by a parent Form.
    'And it returns Menu Object.
    '''''''''''''''''''''''''    '''''''''''''''''''''''''''''''''''''''''''
    Public Function LoadDynamicMenu()
        Dim oXmlElement As Xml.XmlElement
        Dim objNode As Xml.XmlNode

        objXML = New Xml.XmlDocument()
        'load the XML Filep; objXML.Load(XMLMenuFile)
        'Get the documentelement of the XML file.
        oXmlElement = CType(objXML.DocumentElement, Xml.XmlElement)
        'loop through the each Top level nodes
        'For ex., File & Edit becomes Top Level nodes
        'And File -> Open , File ->Save will be treated as 
        'child for the Top Level Nodes
        For Each objNode In objXML.FirstChild.ChildNodes
            'Create a New MenuItem for Top Level Nodes
            mItem = New MenuItem()
            ' Set the caption of the menu items.
            mItem.Text = objNode.Attributes("id").Value
            ' Add the menu items to the main menu.
            mainMenu.MenuItems.Add(mItem)
            'Call this Method to generate child nodes for
            'the top level node which was added now(mItem in the above Add 
            'statement)
            GenerateMenusFromXML(objNode, _
                    mainMenu.MenuItems(mainMenu.MenuItems.Count - 1))
        Next
        'return this Menu handle to the parent Form so that
        'generated menu gets displayed in the Form
        Return objMenu
    End Function

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'This method takes care of loading Menus based on XML file contents. 
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Private Sub GenerateMenusFromXML(ByVal objNode As Xml.XmlNode, _
                                     ByVal mItm As MenuItem)
        'This method will be invoked in an recursive fashion
        'till all the child nodes are generated. This method
        'drills up to N-levels to generate all the Child nodes
        Dim objNod As Xml.XmlNode
        Dim sMenu As New MenuItem()
        'loop for child nodes
        For Each objNod In objNode.ChildNodes
            sMenu = New MenuItem()
            ' Set the caption of the menu items.
            sMenu.Text = objNod.Attributes("id").Value
            mItm.MenuItems.Add(sMenu)
            'Add a Event handler to the menu item added
            'this method takes care of Binding Event Name(based on the 
            'parameter from XML file) to newly added menu item.
            'for ex., Your Form Code should have a 
            '  Private sub MenuItemOnClick_New even to handle
            'the click of New Menu Item
            If Not objNod.Attributes("OnClick") Is Nothing Then
                FindEventsByName(sMenu, objForm, True, "MenuItemOn", _
                    objNod.Attributes("OnClick").Value)
            End If
            'call the same method to see you have any child nodes
            'for the particular node you have added now(above mItm)
            GenerateMenusFromXML(objNod, _
                    mItm.MenuItems(mItm.MenuItems.Count-1))
        Next
        'assign the generated mainMenu object to objMenu - public object
        'which is to be used in the Main Form
        objMenu = mainMenu
    End Sub<

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'objective of this method is to find out the private event present in 
    'Form and attach the newly added menuitem to this event, this was 
    'achieved using Reflection technique
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Private Sub FindEventsByName(ByVal sender As Object, _
     ByVal receiver As Object, ByVal bind As Boolean, _
     ByVal handlerPrefix As String, ByVal handlerSufix As String)
        ' Get the sender's public events.
        Dim SenderEvents() As System.Reflection.EventInfo = 
                                                sender.GetType().GetEvents()
        ' Get the receiver's type and lookup its public
        ' methods matching the naming convention:
        '  handlerPrefix+Click+handlerSufix
        Dim ReceiverType As Type = receiver.GetType()
        Dim E As System.Reflection.EventInfo
        Dim Method As System.Reflection.MethodInfo
        For Each E In SenderEvents
            Method = ReceiverType.GetMethod( _
              handlerPrefix & E.Name & handlerSufix, _
              System.Reflection.BindingFlags.IgnoreCase Or _
              System.Reflection.BindingFlags.Instance Or _
              System.Reflection.BindingFlags.NonPublic)

            If Not Method Is Nothing Then
                Dim D As System.Delegate = _
                     System.Delegate.CreateDelegate(E.EventHandlerType, _
                                                    receiver, Method.Name)
                If bind Then
                    'add the event handler
                    E.AddEventHandler(sender, D)
                Else
                    'you can also remove the event handler if you pass bind
                    'variable as false
                    E.RemoveEventHandler(sender, D)
                End If
            End If
        Next
    End Sub
End Class

LoadDynamicMenu is the main method which will gets invoked from VB.NET Form. It’s a function which returns the Menu handle and it should be assigned to the Me.Menu property.

You can open a New VB.NET Windows Application Project and add the above DynamicMenu.vb to the Project and just paste the below code in Form, it will generate a Dynamic Menu and will associate it to the Form.

VB.NET
Private Sub Form1_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
    Dim objMenu As New DynamicMenu()
    'pass the location of the XML Menu - Configuration File
    objMenu.XMLMenuFile = "D:\DynamicMenu\Menu.xml"
    'pass the Form object to Dynamic Menu so as to associate the Menu _
    'Event handlers
    objMenu.objForm = Me
    'Load dynamic menu and return the Menu handle to Me.Menu object
    Me.Menu = objMenu.LoadDynamicMenu()
End Sub

'whenever user clicks New Menu Item - the below event will get triggered
Private Sub MenuItemOnClick_New(ByVal sender As Object, _
                ByVal e As System.EventArgs)
    MessageBox.Show("New Clicked")
End Sub

'whenever user clicks Paste Menu Item - the below event will get
'triggered
Private Sub MenuItemOnClick_Paste(ByVal sender As Object, _
                ByVal e As System.EventArgs)
    MessageBox.Show("Paste Clicked")
End Sub

'whenever user clicks Test Menu Item - the below event will get triggered
Private Sub MenuItemOnClick_Test(ByVal sender As Object, _
                ByVal e As System.EventArgs)
    MessageBox.Show("Test Clicked")
End Sub

In the above code, we are creating an object objMenu for DynamicMenu Class and we are informing the location of XML Configuration File through XMLMenuFile property to the DynamicMenu Class and finally we invoke LoadDynamicMenu() function which returns the Generated Menu Handle. It will be assigned back to the Me.Menu property and you are ready to use the Menus.

Just a snapshot of how the generated menus look like in the Form:

Sample Image - DynamicMenu.jpg

The dynamic menu generation logic works in the below way, it basically follows Recursion technique:

  1. Load the XML document
  2. Loop the Top Level nodes (in this case, it’s File & Edit)
  3. Add MenuItem for the Top level node (let's say File)
    1. For each Top level node, loop child nodes (for example, New, Open)
    2. Add MenuItem New/Open to parent File node
    3. Create EventHandlers for the newly created Menu Item based on the OnClick Attribute.
    4. Call step 2a using Recursion logic and drill down to N-levels, i.e., loop till you reach the end node.
  4. Retrieve the Generated Menu handle
  5. Assign the generated Menu handle to Me.Menu property so as to display the Menu in the Form.

GenerateMenusFromXML method is invoked recursively for each node to find out whether ChildNodes exists for each node, if Child Nodes exist, then it gets added as a MenuItem and further drilled down till it doesn’t return any ChildNodes.

You can add more elements/nodes to the XML file and you can generate Menu elements based on your requirement. It can support N-levels (File->Open->SubMenu->SubMenu and so on) as it’s a completely dynamic in nature which doesn't have any hardcoding. Since it’s a re-usable component, it can be used across various applications.

References

Please refer to MSDN for more information here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
Web Developer
India India
I am a software professional and have worked on Microsoft & Oracle Technologies for about eight years now. I have always been enthralled by Microsoft technologies and with the advent of .NET , my interest has reached new heights. I take a lot of interest in reading technical articles and equally enjoy writing them.





Comments and Discussions

 
QuestionWebsite on an onclick Event Pin
Doener2k8-May-14 20:35
Doener2k8-May-14 20:35 
QuestionThanks Pin
Anil B. Patil5-Dec-11 23:54
Anil B. Patil5-Dec-11 23:54 
Generalquery Pin
rachanatj4-Sep-08 3:17
rachanatj4-Sep-08 3:17 
GeneralCreating Dynamic menu in vb.Net Pin
poonams29-Oct-07 1:57
poonams29-Oct-07 1:57 
GeneralRe: Creating Dynamic menu in vb.Net Pin
ilovemyindia13-Jul-08 7:32
ilovemyindia13-Jul-08 7:32 
GeneralUsing MenuStrip Pin
uniquekaiser1-Mar-07 16:56
uniquekaiser1-Mar-07 16:56 
GeneralBackground color Pin
keithljarvis31-Jan-07 9:58
keithljarvis31-Jan-07 9:58 
QuestionExtend control = Increase flexibility Pin
Storm-E29-Jan-07 5:10
Storm-E29-Jan-07 5:10 
GeneralNo Subject Pin
Storm-E29-Jan-07 2:03
Storm-E29-Jan-07 2:03 
GeneralNice one....More Info mate Pin
vijayalaya29-Jan-07 0:15
vijayalaya29-Jan-07 0:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.