Build an AJAX-Enabled CMS with Visual WebGUI: Adding Menu Components (II)

Build an AJAX-Enabled CMS with Visual WebGUI: Adding Menu Components (II)

One of the basic components of any application is the menu system. It allows users to navigate across the application and launch the modules. Menu components should be customizable both on look and feel and functionality, and user should be able to develop and integrate them easily into application.The MiniCMS system begun in the first article in this series needs to have flexible menu components.

In the previous article, I designed and implemented the functionality of two elements of the menu system, as required by the MVC pattern: components handling the Model (menu configuration data) and the Controller, and also defined the interfaces to be implemented by the View part — actual menu control for user interace. Now I will create few implementations for the View part of the menu system — the actual components visible to the end user, which implements the functionality of the menu in the application.

Thanks to the modular approach of the menu system, we can create various menu View components, which, as long as you implement the same interface, can be integrated with the menu controller.

In the previous article I defined the two interfaces that define the View part of the menus: IWTMenu and IWTMenuItem. In this part I will create a few implementations for the menu’s View part, and design a small application empowering the menu components.

Implementing the WTTreeMenu component

The WTTreeMenu creates a menu that resembles the behavior of a tree menu. It extends the TreeView control, and implements the IWTMenu interface. The class diagram for the menu is shown in Figure 1.

Figure 1: Class diagrams for WTTreeMenu and WTTreeMenuItem.

We need to implement two components: the menu component WTTreeMenu and WTTreeMenu Item. Table 1 shows the public members of WTTreeMenu. Basically, the public interface of the menu just implements the interface IWTMenu.

Table 1: Public members of WTTreeMenu control.

Table 2 shows the public members of WTTreeMenuItem, which implements the properties defined in the IWTMenuItem interface.

Table 2: Public members of WTTreeMenuItem component.

The constructor is defined below. In the constructor I register the event handler for NodeMouseClick event, which is what we need to detect menu item selection.

public class WTTreeMenu : TreeView, IWTMenu { ?// Constructor ?public WTTreeMenu() : base() { ???this.NodeMouseClick +=  ???????new TreeNodeMouseClickEventHandler(MenuItemMouseClick); ?// ...}

The methods implementing the IWTMenu interface are simple, and are mainly warppers around private methods. InitMenu method just calls the FillTree private method, then set the initial status of the menu based on ExpandMode property.

public void InitMenu(List menuDefinition){ ?Nodes.Clear(); ?FillTree(Nodes, menuDefinition); ?if (m_expandMode == WTTreeExpandMode.MenuMode) ???CollapseAll(); ?else if (m_expandMode == WTTreeExpandMode.TreeMode) ???ExpandAll();}

The main workhorse here is FillTree. It is developed as recursive method, processing any object from the current level and calling recursive for sub-levels. For each entry in menuDef list, a new WTTreeMenuItem is created, attached to the currect Nodes collection, then if the current menu definition objects has child sub-menus, a recursive call is made to generate the menu entries for submenus. When the menu item was added to the menu, it fires MenuItemAdded event, which allow application to bind custom handler to perform additional processing on the menuitem. For example, the application might want to set the menu item with specific properties to customize its look. Through the binding between menu component and menu controller presented in previous article, the event fires back to controller, which is where the custom event handler should be bind to.

private void FillTree( ?TreeNodeCollection treeNodeCollection,  ?List menuDef){ ?// for each menu entry definition ?foreach (IWTMenuEntryDefinition menuEntryDef in menuDef){ ???// create the menu item object ???WTTreeMenuItem menuItem = new WTTreeMenuItem(menuEntryDef); ???// set various properties as TreeNode (the default font) ???TreeNode node = menuItem as TreeNode; ???if (node != null) ?????node.NodeFont = new System.Drawing.Font(this.Font.Name, this.Font.Size); ???// and add it to menu ???treeNodeCollection.Add(menuItem); ???// fire event on menu item adding ??? ???OnMenuItemAdded(menuItem); ???// if menu has child items, create the sub-memu ???if (menuEntryDef.HasChildMenus) ?????FillTree(menuItem.Nodes, menuEntryDef.ChildMenus); ?}}

When a menu item is selected, MenuItemSelected event is fired and the controller is notified, and it gets the reference to the menu item through WTMenuEventArgs parameter. The controller loads the corresponding module, which is linked back to the menu item through LinkedModule property. If user starts another module (by selecting another menu item) and leave some modules open, they became inactive. If later user selects again the menu entry for a module already loaded, the controller just activate the corresponding module.

When user closes a module, it must be detached from the corresponding menu item. This is accomplished through method DetachModule. It receives the reference to module to be detached, finds the associated menu item and un-link them. DetachModule scans the nodes collection of the tree menu recursively, to find associated menu item.

public bool DetachModule(IWTModule module){ ?return DetachModule(Nodes, module);}private bool DetachModule(TreeNodeCollection nodes, IWTModule module){ ?bool nodeFound = false; ?// for each menu item on current level ?foreach (TreeNode tn in nodes){ ???WTTreeMenuItem menuItem = tn as WTTreeMenuItem; ???if (menuItem != null) { ?????// if we found the linked module, detach it  ?????// and select parent menu item as active menu  ?????if (menuItem.LinkedModule == module) { ???????menuItem.LinkedModule = null; ???????SelectedNode = tn.Parent; ???????nodeFound = true; ???????break; ?????} ?????// if not found but currect menu item has sub-menus ?????// search in sub-menus ?????else if (tn.HasNodes) { ???????nodeFound = DetachModule(tn.Nodes, module); ???????if (nodeFound) ?????????break; ?????} ???} ?} ?return nodeFound;}

The actual functionality as menu is accomplished by intercepting NodeMouseClick event of TreeView, handled by MenuItemMouseClick method. When node click is detected, the menus react depending on ExpandMode property, then fire MenuItemClick event.

private void MenuItemMouseClick(object sender, TreeNodeMouseClickEventArgs e){ ?if (m_expandMode == WTTreeExpandMode.MenuMode){ ???CollapseAll(); ???ExpandBranch(e.Node); ?} ?IWTMenuItem menuItem = e.Node as IWTMenuItem; ?OnMenuItemClick(menuItem);}

If ExpandMode is MenuMode, only current menu branch should be expanded, and this all other tree branches must be collapsed.

private void ExpandBranch(TreeNode currentNode){ ?ExpandBranch(currentNode.Parent); ?if (currentNode.HasNodes) ???currentNode.Expand();}

Because the menu is actually a Treeview, you can customize it. In Figures 2, 3, and 4 you can see WTTreeMenu look based on various settings:

    * Figure 2: Menu with ExpandMode = TreeMode and show Plus/Minus signs (for nodes with sub-items

    * Figure 3: Menu with ExpandMode = MenuMode and show Plus/Minus signs (for nodes with sub-items

    * Figure 4: Menu with ExpandMode = TreeMode and hide Plus/Minus signs.

Figure 2: Menu with ExpandMode = TreeMode and show Plus/Minus signs (for nodes with sub-items

Figure 3: Menu with ExpandMode = MenuMode and show Plus/Minus signs (for nodes with sub-items

Figure 4: Menu with ExpandMode = TreeMode and hide Plus/Minus signs.

The WTTreeMenuItem class is derived from TreeNode. Its code contains just the properties defined by the interface IWTMenuItem. Figure 5 shows the sample application included in the download file, using WTTreeMenu.

Figure 5: Sample application using WTTreeMenu component.

WTIconPanelMenu Menu Component

The IconPanel component allows you to develop interfaces that feature Windows Control-Panel like behavior. It displays a list of icons arranged from left to righ and top to bottom. It partly ressembles the functionality of ListView control in LargeIcons mode, but with the advantage that the icons are not limited to 32 x 32 pixels, but can be at any size.

Using the IconPanel and IconPanelItem controls I implemented WTIconPanelMenu. At a certain moment, the menu shows the items on a certain level, and a first item, Back which allow to return to upper level.

In Figure 6, the right panel is shown a WTIconPanelMenu, created from the menu definition for Security tree menu. If users click in the right panel on Security icon, the IconPanel menu will show next menu level, as in Figure 7. Using the Back button, the user can return to the upper level.

Figure 6: Sample application using WTIconPanelMenu in right panel. By clicking on Security icon, the WTIconPanelMenu will show the submenu.

Figure 7: Sample application using WTIconPanelMenu in right panel, shown submenu ofSecurity menu item. By clicking on Back icon, the WTIconPanelMenu will reload the meni items on the first level.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist