Vai al contenuto

Menu dell'Add-on

I menu personalizzati permettono al tuo add-on di integrarsi direttamente nell'interfaccia di SAP Business One, aggiungendo voci sotto il menu Moduli.


1. Struttura dei Menu in SAP B1

Il menu di SAP Business One è un albero gerarchico. Ogni voce è un MenuItem identificato da un ID univoco (stringa). SAP riserva degli ID per i menu di sistema — quello che ci interessa è:

ID Menu
43520 Moduli — il contenitore principale dove gli add-on aggiungono le proprie voci

Come visualizzare l'id dei menu

Attiva le informazioni di sistema da View > Informazioni di sistema (CTRL + SHIFT + I). Poi passa con il mouse sopra al menu nella toolbar e visualizza in basso il suo ID

Per aggiungere un menu personalizzato, la logica è:

  1. Recuperare il MenuItem del menu "Moduli" tramite il suo ID
  2. Accedere ai suoi SubMenus
  3. Aggiungere le proprie voci con Add()

2. Tipi di Voce: BoMenuType

Ogni voce di menu ha un tipo che ne determina il comportamento:

Tipo Descrizione
mt_POPUP Voce contenitore — ha un sottomenu. Non è cliccabile di per sé.
mt_STRING Voce cliccabile — genera un MenuEvent quando l'utente ci clicca.
mt_SEPERATOR Linea separatrice visiva tra le voci. Non è cliccabile.

3. Il Codice Completo: AddOnMenu.cs

using System;
using SAPbouiCOM.Framework;

namespace MySAPAddon
{
    internal class AddOnMenu
    {
        public void AddMenuItems()
        {
            SAPbouiCOM.MenuItem oMenuItem = Application.SBO_Application.Menus.Item("43520"); // Menu Moduli
            SAPbouiCOM.Menus oMenus = oMenuItem.SubMenus;

            // solo per debug, per non chiudere e riaprire SAP ogni volta
            if (oMenus.Exists("RS_MENU1"))
                oMenus.RemoveEx("RS_MENU1");

            // voce principale (contenitore)
            oMenus.Add("RS_MENU1", "Il Mio Add-on", SAPbouiCOM.BoMenuType.mt_POPUP, -1);

            // sottomenu
            oMenus = Application.SBO_Application.Menus.Item("RS_MENU1").SubMenus;
            oMenus.Add("RS_MENU1_SUB1", "SubMenu 1", SAPbouiCOM.BoMenuType.mt_STRING, -1);
            oMenus.Add("RS_MENU1_SUB2", "SubMenu 2", SAPbouiCOM.BoMenuType.mt_SEPERATOR, -1);
            oMenus.Add("RS_MENU1_SUB3", "SubMenu 3", SAPbouiCOM.BoMenuType.mt_STRING, -1);
            oMenus.Add("RS_MENU1_SUB4", "SubMenu 4", SAPbouiCOM.BoMenuType.mt_POPUP, -1);

            // sottomenu del sottomenu
            oMenus = Application.SBO_Application.Menus.Item("RS_MENU1_SUB4").SubMenus;
            oMenus.Add("RS_MENU1_SUB4_SUB1", "Sub sub Menu 1", SAPbouiCOM.BoMenuType.mt_STRING, -1);
            oMenus.Add("RS_MENU1_SUB4_SUB2", "Sub sub Menu 2", SAPbouiCOM.BoMenuType.mt_SEPERATOR, -1);
            oMenus.Add("RS_MENU1_SUB4_SUB3", "Sub sub Menu 3", SAPbouiCOM.BoMenuType.mt_STRING, -1);
        }

        public void SBO_Application_MenuEvent(ref SAPbouiCOM.MenuEvent pVal, out bool BubbleEvent)
        {
            BubbleEvent = true;

            try
            {
                if (pVal.BeforeAction == false && pVal.MenuUID == "RS_MENU1_SUB1")
                {
                    // Qui istanzieremo e mostreremo la nostra Form
                }
            }
            catch (Exception ex)
            {
                Application.SBO_Application.MessageBox(ex.ToString(), 1, "Ok", "", "");
            }
        }
    }
}

Nel Program.cs, registri l'handler così:

AddOnMenu menu = new AddOnMenu();
menu.AddMenuItems();
app.RegisterMenuEventHandler(menu.SBO_Application_MenuEvent);

4. Spiegazione del Codice

Aggiungere le voci: AddMenuItems()

Il metodo Menus.Add() ha questa firma:

oMenus.Add(
    string UniqueID,       // ID univoco della voce (lo usi per identificarla negli eventi)
    string Name,           // Testo visualizzato nel menu
    BoMenuType Type,       // mt_POPUP, mt_STRING o mt_SEPERATOR
    int Position           // -1 = in fondo, altrimenti posizione specifica
);

La logica per creare un menu gerarchico è semplice:

  1. Recuperi il menu padreApplication.SBO_Application.Menus.Item("43520") ti dà il menu "Moduli"
  2. Aggiungi una voce mt_POPUP — questa sarà il contenitore del tuo add-on
  3. Navighi nei SubMenus — per aggiungere le sotto-voci, recuperi la voce appena creata e accedi ai suoi SubMenus
  4. Annidi a piacere — una voce mt_POPUP può contenere a sua volta altri mt_POPUP, permettendo strutture a più livelli

Il trucco RemoveEx per il debug

SAP non permette di aggiungere un menu con un ID che esiste già — otterresti un'eccezione. Chiamando RemoveEx prima di Add, puoi riavviare l'add-on in debug senza dover chiudere e riaprire il client SAP ogni volta.

Gestire i click: SBO_Application_MenuEvent

Il MenuEvent viene scatenato due volte da SAP per ogni click:

Fase BeforeAction Quando
Prima true Prima che SAP esegua l'azione. Puoi bloccarla con BubbleEvent = false.
Dopo false Dopo che l'azione è stata completata. È qui che reagiamo.

Per i menu personalizzati, ci interessa quasi sempre solo la fase dopo (BeforeAction == false). Il MenuUID ti dice quale voce è stata cliccata.

BubbleEvent controlla la propagazione dell'evento: impostandolo a true l'evento continua normalmente, con false SAP blocca l'azione. Per i menu custom lascialo sempre a true.

Il pattern Before/After

Questo pattern è una costante in tutta la UI API di SAP, non solo nei menu. Lo ritroverai negli eventi delle form, degli item, ecc. Serve per darti la possibilità di validare o bloccare un'azione prima che SAP la esegua, oppure di reagire dopo.


5. Struttura Risultante

Il codice sopra genera questa struttura nel menu Moduli di SAP:

📂 Moduli
└── 📂 Il Mio Add-on          (mt_POPUP)
    ├── 📄 SubMenu 1           (mt_STRING)     → genera MenuEvent
    ├── ── ── ── ──            (mt_SEPERATOR)
    ├── 📄 SubMenu 3           (mt_STRING)     → genera MenuEvent
    └── 📂 SubMenu 4           (mt_POPUP)
        ├── 📄 Sub sub Menu 1  (mt_STRING)     → genera MenuEvent
        ├── ── ── ── ──        (mt_SEPERATOR)
        └── 📄 Sub sub Menu 3  (mt_STRING)     → genera MenuEvent