Buenas, apreciado Julian… Ok, te comparto algunas capturas y el código de mi proyecto de prueba.
using System;
using SAPbouiCOM;
using SAPbouiCOM.Framework;
using System.Windows.Forms;
namespace PlanifProdAddon
{
[FormAttribute("PlanifProdAddon.Form1", "Form1.b1f")]
class Form1 : UserFormBase
{
private Timer _cflTimer;
private bool cflActivado = false;
private SAPbouiCOM.Matrix Matrix0;
public Form1()
{
}
public override void OnInitializeComponent()
{
// Vincula el control visual de la matrix desde el diseñador
this.Matrix0 = ((SAPbouiCOM.Matrix)(this.GetItem("mtx_Planif").Specific));
this.UIAPIRawForm.Mode = BoFormMode.fm_ADD_MODE;
this.OnCustomInitialize();
}
public override void OnInitializeFormEvents()
{
// Suscribe el evento global para CFL
SAPbouiCOM.Framework.Application.SBO_Application.ItemEvent += SBO_Application_ItemEvent;
}
private void OnCustomInitialize()
{
this.UIAPIRawForm.Mode = BoFormMode.fm_ADD_MODE;
// Crear el DataTable si no existe
bool existeDT = false;
for (int i = 0; i < this.UIAPIRawForm.DataSources.DataTables.Count; i++)
{
if (this.UIAPIRawForm.DataSources.DataTables.Item(i).UniqueID == "dtPlanif")
{
existeDT = true;
break;
}
}
if (!existeDT)
{
this.UIAPIRawForm.DataSources.DataTables.Add("dtPlanif");
}
SAPbouiCOM.DataTable dt = this.UIAPIRawForm.DataSources.DataTables.Item("dtPlanif");
bool existeColumna = false;
for (int i = 0; i < dt.Columns.Count; i++)
{
if (dt.Columns.Item(i).Name == "codigo")
{
existeColumna = true;
break;
}
}
if (!existeColumna)
{
dt.Columns.Add("codigo", BoFieldsType.ft_AlphaNumeric, 50);
}
// Crear ChooseFromList si no existe
if (!CFL_Existe("CFL_Prod"))
{
ChooseFromListCreationParams cflParams =
(ChooseFromListCreationParams)SAPbouiCOM.Framework.Application.SBO_Application.CreateObject(
BoCreatableObjectType.cot_ChooseFromListCreationParams);
cflParams.MultiSelection = false;
cflParams.ObjectType = "4"; // OITM
cflParams.UniqueID = "CFL_Prod";
this.UIAPIRawForm.ChooseFromLists.Add(cflParams);
}
// Asociar columna visual a campo del DataTable
SAPbouiCOM.Column col = Matrix0.Columns.Item("col_Cod");
col.DataBind.Bind("dtPlanif", "codigo");
col.Editable = true;
// Asignar CFL a la columna
EditTextColumn colCod = col as EditTextColumn;
if (colCod != null)
{
colCod.ChooseFromListUID = "CFL_Prod";
colCod.ChooseFromListAlias = "ItemCode";
}
// Agregar fila si está vacío
if (dt.Rows.Count == 0)
{
dt.Rows.Add();
}
// Cargar la matrix después de modificar el DataTable
Matrix0.LoadFromDataSource();
// Activar clic solo si:
// - Hay filas en el DataTable
// - La matrix tiene por lo menos una fila visual visible
// - El formulario está en modo adecuado
if (Matrix0.RowCount > 0 && this.UIAPIRawForm.Mode == BoFormMode.fm_ADD_MODE)
{
try
{
// Asegurar que la celda esté activa antes del click
//Matrix0.Columns.Item("col_Cod").Cells.Item(1).Click(BoCellClickType.ct_Regular);
}
catch (Exception ex)
{
// Mostrar mensaje en la barra de SAP en lugar de lanzar error
SAPbouiCOM.Framework.Application.SBO_Application.StatusBar.SetText(
"Error al activar CFL automáticamente: " + ex.Message,
BoMessageTime.bmt_Short,
BoStatusBarMessageType.smt_Error);
}
}
// Agregar fila si está vacío
if (dt.Rows.Count == 0)
{
dt.Rows.Add();
Matrix0.LoadFromDataSource();
}
// Activar CFL automáticamente usando un Timer
_cflTimer = new Timer();
_cflTimer.Interval = 500; // medio segundo
_cflTimer.Tick += (s, e) =>
{
try
{
Matrix0.Columns.Item("col_Cod").Cells.Item(1).Click(BoCellClickType.ct_Regular);
}
catch (Exception ex)
{
SAPbouiCOM.Framework.Application.SBO_Application.StatusBar.SetText(
"Error al activar CFL automáticamente: " + ex.Message,
BoMessageTime.bmt_Short,
BoStatusBarMessageType.smt_Error);
}
finally
{
_cflTimer.Stop();
}
};
_cflTimer.Start();
}
private bool CFL_Existe(string uid)
{
try
{
var test = this.UIAPIRawForm.ChooseFromLists.Item(uid);
return test != null;
}
catch
{
return false;
}
}
private void SBO_Application_ItemEvent(string FormUID, ref ItemEvent pVal, out bool BubbleEvent)
{
BubbleEvent = true;
// ⚠️ Evitar errores si pVal es null
// ⚠️ Validar que el formulario esté cargado antes de usarlo
if (this.UIAPIRawForm == null || pVal == null)
return;
// ⚠️ Validar el evento de activación del formulario y que no sea BeforeAction
if (FormUID == this.UIAPIRawForm.UniqueID &&
pVal.EventType == BoEventTypes.et_FORM_ACTIVATE &&
!pVal.BeforeAction &&
!cflActivado) // ← bandera para ejecutar una sola vez
{
try
{
// Activar el ChooseFromList automáticamente haciendo clic programático
Matrix0.Columns.Item("col_Cod").Cells.Item(Matrix0.RowCount).Click(BoCellClickType.ct_Regular);
cflActivado = true;
}
catch (Exception ex)
{
SAPbouiCOM.Framework.Application.SBO_Application.StatusBar.SetText(
"Error al activar CFL automáticamente: " + ex.Message,
BoMessageTime.bmt_Short,
BoStatusBarMessageType.smt_Error);
}
}
// 🎯 Aquí continúa el resto de tu lógica para capturar los valores del CFL
if (FormUID == this.UIAPIRawForm.UniqueID &&
pVal.EventType == BoEventTypes.et_CHOOSE_FROM_LIST &&
!pVal.BeforeAction)
{
try
{
IChooseFromListEvent cfl = (IChooseFromListEvent)pVal;
DataTable oDataTable = cfl.SelectedObjects;
if (oDataTable == null || oDataTable.Rows.Count == 0)
return;
string itemCode = oDataTable.GetValue("ItemCode", 0).ToString();
string itemName = oDataTable.GetValue("ItemName", 0).ToString();
string uom = oDataTable.GetValue("SalUnitMsr", 0).ToString();
int row = pVal.Row - 1;
if (row >= 0 && row < Matrix0.RowCount)
{
SAPbouiCOM.DataTable dt = this.UIAPIRawForm.DataSources.DataTables.Item("dtPlanif");
dt.SetValue("codigo", row, itemCode);
dt.SetValue("descripcion", row, itemName);
dt.SetValue("unidad", row, uom);
Matrix0.LoadFromDataSource();
}
}
catch (Exception ex)
{
SAPbouiCOM.Framework.Application.SBO_Application.StatusBar.SetText(
"Error al capturar valores del CFL: " + ex.Message,
BoMessageTime.bmt_Short,
BoStatusBarMessageType.smt_Error);
}
}
}
Como verán, a modo de realizar la prueba de funcionamiento, lo que hice fue intentar probar con un sólo campo lo del ChooseFromList… Honestamente no manejo mucho lo de la matrix, el datatable y el CFL y este código fue generado por una IA, pero probablemente el código no respeta o no sigue algún orden cronológico que el SAP requiera o reconozca para que pueda funcionar correctamente el evento.
Si se fijan, la columna de código aparece en blanco pero no me deja escribir nada y tampoco aparece el CFL.
Como dije, sería muy útil si pudieran iluminarme y proveerme la estructura base o los criterios que debo considerar para que lo que necesito hacer funcione, que es básicamente crear una matrix dentro de un form nuevo (sea con datatable o userdatasource) y asociar el CFL para la columna de código y descripción (simulando una grilla nativa de SAP para cargar los productos)… Ojalá me haya explicado correctamente para que puedan brindarme su ayuda…
Desde ya, gracias totales.