Sistema Eventi (Event Dispatchers)¶
Il framework Ribes adotta un'architettura basata sul pattern Dispatcher per instradare gli eventi provenienti da SAP Business One ai gestori (handler) registrati. Questo approccio permette di separare la logica dell'applicazione dalla complessa gestione e ricezione degli eventi B1, rendendo il codice più pulito, modulare e facile da mantenere.
Panoramica dell'Architettura¶
Invece di avere un unico grande blocco switch/case che intercetta tutti gli eventi e li devia alla finestra corretta (il classico approccio B1), il Framework utilizza classi dedicate (Dispatcher) che si iscrivono nativamente agli eventi di SAPbouiCOM.Application.
Ogni Dispatcher mantiene un proprio "registro" (una Dictionary o tabella di hash) che mappa una specifica combinazione di parametri (es. FormType, EventType, ItemUID) al metodo delegato che deve eseguirlo.
flowchart LR
A[SAP Event (es. ItemEvent)] --> B(EventDispatcher)
B --> C{Dictionary Lookup}
C -- Match trovato --> D[Invocazione Delegate]
D --> E[BubbleEvent (propagazione)]
I Dispatcher¶
Il framework fornisce una serie di Dispatcher specializzati, ciascuno responsabile per una specifica categoria di eventi. Tutti questi sono raggruppati all'interno della classe contenitore principale EventDispatcher.
ItemEventDispatcher: Gestisce gli eventi legati agli elementi delle form (click, modifiche, focus, form load, form close, ecc.).MenuEventDispatcher: Gestisce gli eventi di click sui menu dell'applicazione SAP.FormDataEventDispatcher: Gestisce gli eventi relativi ai dati della form (load, add, update, delete).AppEventDispatcher: Intercetta gli eventi a livello di applicazione (es. spegnimento, cambio azienda).RightClickEventDispatcher: Gestisce gli eventi di click destro (context menu).PrintEventDispatcher: Gestisce gli eventi di stampa.StatusBarEventDispatcher: Gestisce gli eventi legati alla barra di stato.
La classe EventDispatcher¶
EventDispatcher.cs è il punto d'ingresso per accedere ai vari dispatcher del framework. È un contenitore centralizzato che viene istanziato all'avvio e mette a disposizione le istanze Singleton dei vari dispatcher specializzati, permettendoti di registrare o deregistrare facilmente gli handler.
Pattern di Registrazione e BubbleEvent¶
Quando si registra un evento, si specifica la condizione in base alla quale la funzione (callback) verrà eseguita (es. quando scatta l'evento et_ITEM_PRESSED sul bottone "1" della form "MiaForm"). Il dispatcher salva questo riferimento nella sua Dictionary.
Al verificarsi dell'evento in SAP:
1. Il Dispatcher riceve l'evento nativo da B1.
2. Crea una chiave di ricerca in base ai parametri in ingresso (FormUID/FormType, EventType, ItemUID).
3. Cerca questa chiave nella sua Dictionary.
4. Se trova un match, esegue il delegato registrato.
Il BubbleEvent¶
Come in tutti gli script SAP B1, il BubbleEvent è cruciale:
- Viene inizializzato di default a true.
- Se una qualsiasi delle callback registrate lo imposta a false, l'esecuzione si interrompe e il Framework restituisce false a SAP (bloccando di fatto l'azione nativa in B1, ad esempio impedendo la chiusura di una form o l'aggiunta di un dato).
Attenzione
L'ordine di esecuzione in caso di registrazioni multiple per lo stesso evento non è strettamente garantito. Fai molta attenzione se due handler per lo stesso bottone tentano entrambi di modificare il BubbleEvent.
Tipi di Delegati (EventDispatcherDelegates)¶
Il file EventDispatcherDelegates.cs definisce i tipi di delegati (le firme dei metodi) che i vari handler devono rispettare.
public static class EventDispatcherDelegates
{
public delegate void SAPItemEventHandler(string formUID, ref SAPbouiCOM.ItemEvent pVal, out bool bubbleEvent);
public delegate void SAPFormDataEventHandler(ref SAPbouiCOM.BusinessObjectInfo boi, out bool bubbleEvent);
public delegate void SAPAppEventHandler(SAPbouiCOM.BoAppEventTypes eventType);
public delegate void SAPMenuEventHandler(ref SAPbouiCOM.MenuEvent pVal, out bool BubbleEvent);
public delegate void SAPPrintEventHandler(ref SAPbouiCOM.PrintEventInfo eventInfo, out bool BubbleEvent);
public delegate void SAPRightClickEventHandler(ref SAPbouiCOM.ContextMenuInfo eventInfo, out bool bubbleEvent);
public delegate void SAPStatusBarEventEventHandler(string Text, SAPbouiCOM.BoStatusBarMessageType MessageType);
}
MenuEventCallback¶
Oltre alla normale registrazione tramite delegati, MenuEventDispatcher espone il supporto anche per una classe MenuEventCallback. Questa classe permette la registrazione di callback passate come testo, una tecnica spesso utilizzata quando i menu vengono caricati dinamicamente o configurati tramite un file XML esterno (reflection).
Esempio Pratico: Registrare un ItemEvent¶
Ecco come registrarsi per catturare il click su un bottone specifico in una form:
// Assumiamo di avere a disposizione la nostra istanza di framework e il FormType o UID
string formType = "MIA_FORM_TYPE";
string buttonUid = "btnSave";
// 1. Recupero del dispatcher
var itemDispatcher = EventDispatcher.ItemEventDispatcher;
// 2. Iscrizione all'evento
itemDispatcher.Subscribe(
formType,
buttonUid,
SAPbouiCOM.BoEventTypes.et_ITEM_PRESSED,
OnSaveButtonPressed
);
// 3. Metodo callback (deve rispettare la firma SAPItemEventHandler)
private void OnSaveButtonPressed(string formUID, ref SAPbouiCOM.ItemEvent pVal, out bool bubbleEvent)
{
bubbleEvent = true;
if (pVal.BeforeAction)
{
// Validazione prima di procedere
if (!DatiValidi())
{
SAPManager.Instance.Application.MessageBox("Dati incompleti!");
bubbleEvent = false; // Blocca l'esecuzione SAP
}
}
else
{
// Azione dopo che l'evento è passato in SAP
SAPManager.Instance.Application.SetStatusBarMessage("Salvataggio completato", SAPbouiCOM.BoMessageTime.bmt_Short, false);
}
}
Suggerimento
Ricordati sempre di de-registrare (usando il metodo Unsubscribe) gli eventi quando la tua finestra si chiude per evitare memory leak o esecuzioni orfane, oppure sfrutta i metodi di gestione del ciclo di vita forniti dalle classi Base Form del framework.