Steps to migrate from the legacy SmartFramework menu rendering to the new implementation
Add method to get a configured instance of the MainMenuRenderer class
The NewMainMenuRenderer method is used to create a new instance of the MainMenuRenderer class and configure it with the settings of your Main Menu Form. If you want to customize the rendering of the menu you can create a class that implements the IMainMenuRenderer interface and create an instance of that class here.
In the reference implementation of the MainMenuRenderer there are settings to customize the default behaviour
Property | Default Value | Description |
---|---|---|
ConstantExplorerBarGroups | "" | Comma delimeted list of constant ExplorerBarGroups that do not get removed if the user is not authorized to see them |
MenuTreeViewControlSortAlphabetical | FALSE | Defines sorting of MenuTreeViewControl. When menu should be sorted by alphabet and not by menu structure provider |
RenderRecentGroup | TRUE | Indicates if the list of last recently used MenuItems should be rendered |
/*------------------------------------------------------------------------------ Purpose: Creates and configures a new instance of the MainMenuRenderer class Notes: @return The configured instance of the MainMenuRenderer class ------------------------------------------------------------------------------*/ METHOD PUBLIC IMainMenuRenderer NewMainMenuRenderer (): DEFINE VARIABLE oMainMenuRenderer AS MainMenuRenderer NO-UNDO. oMainMenuRenderer = NEW MainMenuRenderer (). oMainMenuRenderer:ConstantExplorerBarGroups = "":U. oMainMenuRenderer:MenuTreeViewControlSortAlphabetical = FALSE. oMainMenuRenderer:RenderRecentGroup = TRUE. RETURN oMainMenuRenderer. END METHOD .
Replace legacy rendering code from AfterShownHandler with the call to MainMenuRenderer
The previous implementation of rendering the Main Menu is located in the AfterShownHandler method. To migrate this method some changes are needed.
Define a new variable for the IMainMenuRenderer instance as follows
DEFINE VARIABLE oMainMenuRenderer AS IMainMenuRenderer NO-UNDO .
The previous SmartFramework rendering code looks similar to the following code block. However it should be surrounded by "&IF DEFINED (SmartFramework) NE 0 &THEN" and "&ENDIF". This block can be replaced with the call to the MainMenuRenderer class.
&IF DEFINED (SmartFramework) NE 0 &THEN ultraExplorerBar1:SuspendLayout() . Consultingwerk.Windows.API.Win32:LockWindowUpdate (THIS-OBJECT) . THIS-OBJECT:InitializeRecentlyUsedMenuItemsGroup ("Recent":U, "Recent"{&TRAN}, "Consultingwerk/Windows/Framework/Images/step_16.png":U, "Consultingwerk/Windows/Framework/Images/step_32.png":U, 0) . ASSIGN i = 1 . DEFINE VARIABLE oGroups AS CharacterHolder NO-UNDO . IF SessionManager:UserGroupKeys > "":U THEN DO: oGroups = NEW CharacterHolder (SessionManager:UserGroupKeys) . FrameworkSettings:ServiceAdapter:InvokeMethod ("":U, "Consultingwerk.SmartFramework.Menu.MenuBusinessEntity":U, "GetMenusForGroups":U, INPUT-OUTPUT DATASET dsMenu, oGroups) . FOR EACH eSmartMenu WHERE eSmartMenu.MenuStyleCode = "":U OR eSmartMenu.MenuStyleCode = "TREE":U OR eSmartMenu.MenuStyleCode = "EXPLORERBAR":U OR eSmartMenu.MenuStyleCode = "TASKLIST":U BY eSmartMenu.MenuSequence: IF eSmartMenu.MenuStyleCode = "":U OR eSmartMenu.MenuStyleCode = "TREE":U THEN THIS-OBJECT:InitializeExplorerBarGroup (eSmartMenu.MenuGuid, eSmartMenu.MenuName, eSmartMenu.MenuGuid, eSmartMenu.MenuSmallImage, eSmartMenu.MenuLargeImage, i, FALSE) . ELSE IF eSmartMenu.MenuStyleCode = "EXPLORERBAR":U THEN THIS-OBJECT:InitializeNativeExplorerBarGroup (eSmartMenu.MenuGuid, eSmartMenu.MenuName, eSmartMenu.MenuGuid, eSmartMenu.MenuSmallImage, eSmartMenu.MenuLargeImage, i) . ELSE THIS-OBJECT:InitializeTaskList (eSmartMenu.MenuGuid, eSmartMenu.MenuName, eSmartMenu.MenuGuid, eSmartMenu.MenuSmallImage, eSmartMenu.MenuLargeImage, i) . i = i + 1 . END. FOR EACH eSmartMenu WHERE eSmartMenu.MenuStyleCode = "RIBBON":U BY eSmartMenu.MenuSequence: THIS-OBJECT:InitializeRibbonTab (eSmartMenu.MenuGuid) . END. END. Consultingwerk.Windows.API.Win32:LockWindowUpdate (0) . ultraExplorerBar1:ResumeLayout(TRUE) . &ENDIF
Replace this code with the new code block calling the MainMenuRenderer
oMainMenuRenderer = NewMainMenuRenderer (). oMainMenuRenderer:RenderMenuStructure (THIS-OBJECT:ultraExplorerBar1, THIS-OBJECT:smartToolbarController1, THIS-OBJECT).
At the end of the method a finally block needs to be inserted if not already existing, to cleanup the instance of the MainMenuRenderer class.
FINALLY: GarbageCollectorHelper:DeleteObject (oMainMenuRenderer). END FINALLY.
However please review the method for unused variables. From the reference implementation there is the "i" variable that is no longer needed and schould be removed
Remove no longer used includes of the dsMenuGroup and dsMenu ProDatasets
If there is no custom code using these two ProDatasets anymore these includes can be removed from the form source code. All customizations should be moved to a MainMenuRenderer derived customization class as mentioned in section 1.
&IF DEFINED (SmartFramework) NE 0 &THEN { Consultingwerk/SmartFramework/Authorization/dsMenuGroup.i } { Consultingwerk/SmartFramework/Menu/dsMenu.i } &ENDIF
Implement functionality to reload the complete menu
If applicable remove the method “ReloadMenu” and replace the call in smartToolbarController1_ToolClick event handler method with the call to the MainMenuRenderer instance as shown in section 2. There is no specialized method to reload the menu. The RenderMenuStructure method will refresh the current menu controls and Ribbon tabs, remove groups and tabs that are not accessible anymore and add newly accessible ones.
DEFINE VARIABLE oMainMenuRenderer AS IMainMenuRenderer NO-UNDO .
WHEN "Reload Menu":U THEN DO: oMainMenuRenderer = NewMainMenuRenderer (). oMainMenuRenderer:RenderMenuStructure (THIS-OBJECT:ultraExplorerBar1, THIS-OBJECT:smartToolbarController1, THIS-OBJECT). END.
FINALLY: GarbageCollectorHelper:DeleteObject (oMainMenuRenderer). END FINALLY.