web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Dynamics 365 Community / Blogs / Hardik’s Dynamics Dojo / The Art of Disappearing Act...

The Art of Disappearing Acts: Dynamic Menu Visibility in Dynamics 365 F&O

HardikPatel523 Profile Picture HardikPatel523 234
Have you ever looked at the standard Dynamics 365 Finance & Operations navigation pane and thought, "Wow, our users really love scrolling through fifty-seven menu items they don't have permission, configuration, or any earthly reason to use"?
No? Neither has anyone else.
Normally, we manage what users see using security roles or standard configuration keys. But what happens when you need to hide or show a menu item based on complex, runtime business logic? For example: “Only show this custom menu item if it’s a Tuesday, the customer’s credit rating is ‘Gold’, and the user has had their morning coffee.”
Today, we are diving deep into the metadata layer of X++ to intercept how D365 builds its menu tree. We will look at how to cleanly extend `MenuElementNode` and `MenuItemReferenceNode` to gain absolute power over what stays and what goes.

The Core Concept: Understanding the Tree

When D365 renders a module menu (like the SalesAndMarketing menu shown below), it evaluates a tree structure of metadata objects.
To control visibility dynamically, we have two primary hooks:
  1. `MenuElementNode`: The base class for structural components of the menu.
  2. `MenuItemReferenceNode`: The specific leaf node that points directly to an actual display, output, or action menu item.




By utilizing Chain of Command (CoC) on these nodes, we can intercept the standard `IsVisible()` method, perform our custom calculations, and cleanly return `true` or `false`.

🛠️ The Blueprints: Implementation Classes

Let's look at the implementation strategy using two targeted extensions.

1. The Generic Hook: Extending `MenuElementNode`

This extension targets the general structural element of the menu tree. It gives you a clean entry point to apply global visibility overrides.

using Microsoft.Dynamics.AX.Metadata.MetaModel;

[ExtensionOf(classStr(MenuElementNode))]
final class HPSysMenuElementNodeCls_Extension
{
    public boolean IsVisible()
    {
        // 1. Let the standard framework run its normal security and config checks first
        boolean ret = next IsVisible();

        // 2. Pass the standard result into our custom evaluator
        ret = this.hpIsVisible(ret);

        return ret;
    }

    private boolean hpIsVisible(boolean _ret)
    {
        // PLACEHOLDER: Insert custom global criteria here
        // Example: if (CompanyInfo::current() == 'DAT') { return false; }

        return _ret;
    }
}

2. The Smart Hook: Extending MenuItemReferenceNode

This is where the real magic happens. This extension evaluates specific menu items. In this example, the code dynamically checks if the menu item is linked to a specific Feature Class, and verifies its status programmatically via reflection (DictClass).

using Microsoft.Dynamics.AX.Metadata.MetaModel;

[ExtensionOf(classStr(MenuItemReferenceNode))]
final class SGSysMenuItemReferenceNodeCls_Extension
{
    public boolean IsVisible()
    {
        // 1. Fetch standard visibility status
        boolean ret = next IsVisible();

        // 2. Apply our dynamic, feature-based override
        ret = this.hpIsVisible(ret);

        return ret;
    }

    private boolean hpIsVisible(boolean _ret)
    {
        // Extract the metadata element properties
        AxMenuElementMenuItem menuItem      = this.GetMetaModelElement();

        // Instantiate the corresponding MenuFunction Object
        MenuFunction          mf            = new MenuFunction(menuItem.MenuItemName, menuItem.MenuItemType);

        // Find if a feature management or toggle class is associated with this menu function
        ClassName             featureClass  = null != mf ? mf.featureClass() : '';
        DictClass             featureDictClass = '' != featureClass ? new DictClass(className2Id(featureClass)) : null;

        // If a feature class exists, use reflection to check its availability status dynamically
        if (null != featureDictClass && featureDictClass.CustomMethod())
        {
            // Call a static check method (e.g., 'isEnabled') on the fly
            return featureDictClass.callStatic(identifierStr(isEnabled));
        }

        return _ret;
    }
}

💡 Real-World Scenario: The VIP Clearance Toggle

Let’s bring this down to earth with a concrete example. Imagine your company has an exclusive menu item called `VIPDiscountConsole` inside the PricesAndDiscounts submenu.
You want this menu item to be visible only if:
1. The legal entity has the "VIP Toggling Feature" turned on in parameters.
2. The current user belongs to a specific User Group (`VIP_Managers`).
Instead of writing complex, hard-to-maintain security policies, your `hpIsVisible` method can look directly at a configuration class:

private boolean hpIsVisible(boolean _ret)
{
    AxMenuElementMenuItem menuItem = this.GetMetaModelElement();

    if (menuItem.MenuItemName == menuItemStr(VIPDiscountConsole))
    {
        // Dynamic Runtime Check
        if (!VIPFeatureToggleParameters::isVipConsoleEnabled() || !MyUserGroupHelper::isCurrentUserVIP())
        {
            return false; // Poof! It vanishes.
        }
    }
    return _ret;
}

⚠️ A Note on Performance

Because `IsVisible()` is called frequently when menus load, keep your code fast and lightweight inside these extensions:
  • Do not write heavy database queries (`select sum(Amount) from CustTrans...`).
  • Do not make web service calls to external systems inside this loop.
  • Do use caching strategies or read from pre-loaded global variables/singleton parameters. (Want to deep dive into caching? If you want to learn how to properly handle caching and prevent your code from hammering the database thousands of times in loops, check out my previous blog post: The Day My Code Called the Database 5000 Times (And How One Cache Fixed It). )

Summary

By extending `MenuElementNode` and `MenuItemReferenceNode`, you elevate control from static security settings to smart, context-aware user interfaces. This keeps workspace interfaces clean, precise, and streamlined for end-users.
Go forth and bend the UI to your will! After all, as developers, we hold the ultimate power: the ability to make our users' problems—and their menu items—vanish into thin air with a single line of code.
Keep your code clean, your caching fast, and remember: if you can control the menu, you can control the world. Now go declutter those workspaces and make the ERP world a slightly less chaotic place, one hidden button at a time!

Comments