Professional Documents
Culture Documents
Dynamics 365 For Finance and Operations Development Cookbook Fourth Edition (1) - 82-145.en - Es
Dynamics 365 For Finance and Operations Development Cookbook Fourth Edition (1) - 82-145.en - Es
com
Introducción
Los formularios en Dynamics 365 for Finance and Operations representan la interfaz de usuario y se usan
principalmente para ingresar o modificar datos. También se utilizan para ejecutar informes, ejecutar
comandos de usuario, validar datos, etc.
Trabajar con formularios
Normalmente, los formularios se crean utilizando AOT produciendo un objeto de formulario y agregando controles de
formulario, como pestañas, páginas de pestañas, cuadrículas, grupos, campos de datos e imágenes. El comportamiento del
formulario está controlado por sus propiedades o el código en sus métodos miembro. El comportamiento y el diseño de los
controles de formulario también están controlados por sus propiedades y el código de sus métodos miembro. Aunque es muy
raro, también se pueden crear formularios dinámicamente a partir de código.
En este capítulo, cubriremos varios aspectos del uso de formularios de Dynamics 365 for Finance and
Operations. Comenzamos creando cuadros de diálogo de Dynamics 365 for Finance and Operations, que en
realidad son formularios dinámicos, y luego pasamos a explicar cómo manejar sus eventos. El capítulo también
le mostrará cómo crear formularios dinámicos, cómo agregar controles dinámicos a formularios existentes y
cómo crear formularios modales.
La clase de aplicación llamadaDiálogose utiliza para construir diálogos. Otras clases de aplicaciones, como
campo de diálogo, grupo de diálogo,yDialogTabPage,se utilizan para crear controles de diálogo. La forma
más fácil de crear diálogos es usar elEjecutarBaseestructura. Esto se debe a que el marco proporciona un
conjunto de métodos predefinidos que hacen que la creación y el manejo del diálogo estén bien
estructurados, en lugar de tener todo el código en un solo lugar.
En este ejemplo, demostraremos cómo construir un diálogo a partir de código usando elEjecutarBase
clase marco. El cuadro de diálogo contendrá los campos de la tabla de clientes que se muestran en
diferentes grupos y pestañas para crear un nuevo registro. Habrá dos páginas de pestañas,Generaly
Detalles.La primera página tendrá laCuenta de clienteyNombrecontroles de entrada La segunda página se
dividirá en dos grupos,ConfiguraciónyPago,con campos relevantes dentro de cada grupo. No se creará el
registro real, ya que está más allá del alcance de este ejemplo. Sin embargo, con fines demostrativos, la
información especificada por el usuario se mostrará en el Registro de informaciónventana.
[ 64 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
devolver verdadero;
}
Cree un método de diálogo para capturar las entradas del usuario en tiempo de ejecución para los detalles del cliente:
Diálogo de objeto ()
{
Diálogo diálogo;
grupo de diálogo grupoCliente;
grupo de diálogo grupoPago;
diálogo = super();
cuentacampo=dialog.addField
[ sesenta y cinco ]
Trabajar con formularios
(extendedTypeStr(CustVendAC),"Cuenta de cliente");
fieldName =dialog.addField(extendedTypeStr(CustName));
diálogo.addTabPage("Detalles");
grupoCliente = dialog.addGroup("Configuración");
fieldGroup=dialog.addField
(extendedTypeStr(CustGroupId));
fieldCurrency=dialog.addField
(extendedTypeStr(CurrencyCode));
grupoPago = dialog.addGroup("Pago");
fieldPaymTermId=dialog.addField
(extendedTypeStr(CustPaymTermId));
fieldPaymMode = dialog.addField
(extendedTypeStr(CustPaymMode));
diálogo de retorno;
}
Ahora, cuando los usuarios seleccionan sus valores deseados, debemos leerlos todos para mostrarlos en el
registro de información. UsargetFromDialogpara leer el valor de un campo de diálogo:
cuentacliente = campoCuenta.valor(); =
nombrecliente nombreCampo.valor();
ID de grupo de clientes = grupocampo.valor();
monedaCódigo = campoDivisa.valor();
paymTermId = fieldPaymTermId.value(); =
modo de pago fieldPaymMode.value();
devolver súper();
[ 66 ]
Trabajar con formularios
si (miDiálogo.prompt())
{
miDiálogo.run();
}
}
}
3. Para probar el diálogo, haga clic derecho en esta clase yestablecer como proyecto de inicio.
4. Construya su proyecto. Ahora, ejecute el proyecto. Aparecerá el siguiente formulario en el
navegador de Internet:
[ 67 ]
Trabajar con formularios
4. Haga clic en elDetallespágina de pestaña; Verá una pantalla similar a la siguiente captura de
pantalla:
5. Ingrese información en todos los campos y haga clic enOK. Los resultados se mostrarán en laRegistro de
informaciónpestaña en la parte superior de la ventana del navegador.
[ 68 ]
Trabajar con formularios
Cómo funciona...
Primero, creamos una nueva clase llamadaMiDiálogo.Al extenderlo desdeEjecutarBase,utilizamos un
enfoque estándar para desarrollar funciones de manipulación de datos en Dynamics 365 for Operations.
losEjecutarBaseframework definirá una estructura común y automáticamente agregará controles
adicionales, como elOKyCancelarbotones, al cuadro de diálogo.
Luego, declaramos las variables miembro de la clase, que se utilizarán más adelante. loscampo de diálogolas variables
de tipo son campos de entrada de usuario reales. El resto de las variables se utilizan para almacenar los valores
devueltos por la entrada del usuario.
El diseño del diálogo real se construye en eldiálogo()método de miembro. Aquí, definimos variables locales
para el propio cuadro de diálogo: pestañas y grupos. Estas variables, a diferencia de los campos de
diálogo, no almacenan ningún valor para su posterior procesamiento. lossúper()en el método crea el objeto
de diálogo inicial para nosotros y agrega automáticamente los controles relevantes, incluido elOKy
Cancelarbotones.
[ 69 ]
Trabajar con formularios
Los valores de los controles de diálogo se asignan a las variables llamando alvalor()
método miembro deCampo de diálogo.Si se utiliza un cuadro de diálogo dentro delEjecutarBaseframework,
como se usa en este ejemplo, el mejor lugar para asignar valores de control de diálogo a las variables es el
getFormDialog()método de miembro. losEjecutarBaseframework llama a este método justo después de que el
usuario haga clic enOK.
El procesamiento principal se realiza en elcorrer()método. Para fines de demostración, esta clase solo muestra la entrada del
usuario en elRegistro de informaciónpestaña en la parte superior de la ventana del navegador.
Para hacer que esta clase sea ejecutable, elprincipal()Se debe crear un método estático. Aquí,
creamos un nuevoCustCreateobjeto e invoque el diálogo de usuario llamando alinmediato()
método. Una vez que el usuario haya terminado de ingresar los datos del cliente haciendo clic enOK, llamamos al
correr()método para procesar los datos.
A menudo, los diálogos existentes deben modificarse para admitir eventos. La forma más sencilla de hacer esto es, por
supuesto, convertir un diálogo en un formulario AOT. Sin embargo, cuando el diálogo existente es lo suficientemente
complejo, una solución más rentable probablemente sería implementar el manejo de eventos de diálogo en lugar de
convertirlo en un formulario AOT. El manejo de eventos en los diálogos no es flexible, como en el caso de los formularios
AOT; pero en la mayoría de los casos, hace el trabajo.
En esta receta, crearemos un cuadro de diálogo similar al cuadro de diálogo anterior, pero en lugar de
ingresar el número de cliente, podremos seleccionar el número de una lista. Una vez seleccionado el
cliente, el resto de campos serán rellenados automáticamente por el sistema a partir de la ficha del cliente.
[ 70 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
1. Agregue una nueva clase llamadaMi selección de diálogocon el siguiente fragmento de código:
DialogField campoCuenta;
Nombre de campo de DialogField;
Grupo de campos DialogField;
DialogField campo Moneda;
DialogField fieldPaymTermId;
DialogField fieldPaymMode;
volver conNull();
}
devolver verdadero;
}
2. Cree un método de diálogo para capturar las entradas del usuario en tiempo de ejecución para los detalles del cliente:
Diálogo de objeto ()
{
Diálogo diálogo;
grupo de diálogo grupoCliente;
grupo de diálogo grupoPago;
diálogo = super();
campoCuenta = dialog.addField
(extendedTypeStr(CustAccount),"Cuenta de cliente");
diálogo.addTabPage("Detalles");
[ 71 ]
Trabajar con formularios
grupoCliente = dialog.addGroup("Configuración");
grupo de campo = dialog.addField
(extendedTypeStr(CustGroupId));
fieldCurrency = dialog.addField
(extendedTypeStr(CurrencyCode));
grupocampo.habilitado(falso);
campoDivisa.habilitado(falso);
grupoPago = dialog.addGroup("Pago");
fieldPaymTermId =dialog.addField
(extendedTypeStr(CustPaymTermId));
fieldPaymMode = dialog.addField
(extendedTypeStr(CustPaymMode));
fieldPaymTermId.enabled(falso);
fieldPaymMode.habilitado (falso);
diálogo de retorno;
}
CustTable custTable;
custTable = CustTable::find(fieldAccount.value());
nombreDeCampo.valor(tablaCliente.nombre());
fieldGroup.value(custTable.CustGroup);
fieldCurrency.value(custTable.Currency);
fieldPaymTermId.value(custTable.PaymTermId);
fieldPaymMode.value(custTable.PaymMode);
}
if (miDialogSelect.prompt()) {
myDialogSelect.run();
}
}
[ 72 ]
Trabajar con formularios
[ 73 ]
Trabajar con formularios
4. Guarde todos sus cambios y cree su proyecto. Ahora ejecute el proyecto. El siguiente formulario
aparecerá en un navegador de Internet.
5. Ejecute el proyecto, seleccione cualquier cliente de la lista y mueva el cursor al siguiente control.
Observe cómo el resto de los campos se completaron automáticamente con la información del
cliente, como se muestra en la siguiente captura de pantalla:
[ 74 ]
Trabajar con formularios
6 Cuando haces clic en elDetallespestaña, verá más información sobre el cliente, como se
muestra en la siguiente captura de pantalla:
Cómo funciona...
La nueva clase denominadaMi selección de diálogoen realidad es una copia delMi diálogoclase de la receta
anterior, con algunos cambios. En su declaración de clase, dejamos todos loscampo de diálogo
declaraciones y eliminar el resto de las variables.
[ 75 ]
Trabajar con formularios
lospaquete()ydeshacer()los métodos siguen siendo los mismos, ya que no estamos utilizando ninguna de sus
funciones.
losdiálogoSeleccionarCtrl()método miembro de laEjecutarBaseLa clase se llama cada vez que el usuario modifica
cualquier control de entrada en el cuadro de diálogo. Es el lugar donde tenemos que agregar todo el código
requerido para garantizar que, en nuestro caso, todos los controles se completen con los datos correctos del
registro del cliente una vez.Cuenta de clientees seleccionado.
Ver también
[ 76 ]
Trabajar con formularios
En esta receta, crearemos un diálogo que tomará ciertos parámetros. Según los parámetros
provistos, el saldo del cliente se mostrará en pantalla al presionar el botón en el formulario
Todos los clientes para Mostrar saldos. Se puede abrir navegando aCuentas por cobrar|
Clientes|Todos los clientes.
preparándose
Usaremos los siguientes artefactos de desarrollo con fines de demostración.
contrato de datos: El contrato de datos (Contrato de datos de saldo de cliente)es la clase modelo
en la que definimos qué atributos necesitamos para nuestra operación, comúnmente
establecidos como parámetros por el usuario en un diálogo. Es solo una clase modelo con un
atributo, en la que usaremos elDataContractAttributeDataContractAttributeatributo para decorar
nuestra declaración de clase. Para cada variable miembro, tenemos que definir un método
parm usando el atributoAtributo de miembro de datos,que funcionará como el método getter
setter. Además, si queremos que haya más métodos disponibles, también podemos extender
la clase estándarSysOperationDataContractBase.Con esta clase, podemos definir cómo se verá
nuestro diálogo básico para el usuario. Podemos definir nuestras etiquetas, grupos, tamaños y
tipos de parámetros.
[ 77 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
[
Atributo de contrato de datos,
SysOperationContractProcessingAttribute
(classStr(CustBalanceUIBuilder)),
SysOperationGroupAttribute
('Fecha',"@ApplicationPlatform:SingleSpace", '1') ]
NoSíId permitirModificarFecha;
transfecha transfecha;
str empaquetadaConsulta;
/// <resumen>
/// Obtiene o establece el valor del parámetro del contrato de datos
FechaFechaTransacción.
/// </resumen>
/// <param nombre="_transDate">
/// El nuevo valor del parámetro contrato de datos
FechaFechaTransacción;
/// </parámetro>
/// <regresa>
/// El valor actual del parámetro del contrato de datos
FechaTransacciónFecha
/// </regresa>
[DataMemberAttribute('DateTransactionDate')
, SysOperationLabelAttribute(literalStr("@SYS11284")),
SysOperationGroupMemberAttribute('Fecha'),
SysOperationDisplayOrderAttribute('1')] // fecha de hoy public TransDate
parmTransDate
(TransDate _transDate = transDate) {
fechatrans = _fechatrans;
volver transfecha;
}
/// <resumen>
/// Obtiene o establece el valor del parámetro del contrato de datos
Control de fecha.
[ 78 ]
Trabajar con formularios
/// </resumen>
/// <param name="_allowModifyDate">
/// El nuevo valor del parámetro contrato de datos
control de fecha;
/// </parámetro>
/// <regresa>
/// El valor actual del parámetro del contrato de datos
control de fecha
/// </regresa>
[DataMemberAttribute('DateControl'),
SysOperationLabelAttribute("Habilitar control de fecha"),
SysOperationGroupMemberAttribute('Date'),
SysOperationDisplayOrderAttribute('0')]
public NoYesId parmAllowModifyDate (NoYesId
_allowModifyDate = allowModifyDate) {
/// <resumen>
/// Valida los valores de diálogo para errores. /// </
resumen>
/// <regresa>
/// falso si ha ocurrido un error en los valores del diálogo;
de lo contrario, cierto.
/// </regresa>
/// <comentarios>
/// Los valores de diálogo se manejan a través del contrato. /// </
comentarios>
validación booleana pública () {
volver ret;
}
empaquetadoQuery = _packedQuery;
volver empaquetadoQuery;
[ 79 ]
Trabajar con formularios
volver nuevo
Consulta(SysOperationHelper::base64Decode(packedQuery));
}
consulta empaquetada
=SysOperationHelper::base64Encode(_query.pack());
}
2. En el proyecto VS, cree una nueva clase llamadaControlador de saldo del clientecon el siguiente
fragmento de código:
Controlador: Como su nombre lo indica, esta clase tiene la gran responsabilidad de iniciar la operación.
Esta clase contiene toda la información sobre el modo de ejecución; debe mostrar un formulario de
progreso o un cuadro de diálogo. Es una buena práctica no escribir todo el inicio de sesión de la empresa
en elControladorclase en sí. Por eso, en esta demostración, hemos creado una clase de servicio para
escribir nuestra lógica empresarial, y esa referencia de clase de servicio se proporciona en este método
principal de clase de controlador.
/// <resumen>
/// Establece los rangos de consulta en función de la persona que
llama. /// </resumen>
/// <param nombre="_consulta">
/// Mantiene el objeto <c>Query</c> del servicio.
[ 80 ]
Trabajar con formularios
/// </parámetro>
setRangos de vacío público () {
QueryBuildDataSource queryBuildDataSource;
FormDataSource custTableDS;
CustTable custTable;
calle rango;
Consulta _consulta;
contrato = this.getDataContractObject() as
CustBalanceDataContract;
_consulta = contrato.getQuery(); si
(esto.parmArgs()
&& this.parmArgs().caller() this.parmArgs().dataset() ==
&& tableNum(CustTable))
{
custTableDS = FormDataUtil::getFormDataSource
(this.parmArgs().record());
custTable = custTableDS.getNext()) {
+ ',' + custTable.AccountNum;
}
si (rango)
{
queryBuildDataSource =
_query.dataSourceTable(tableNum(CustTable));
// verificar QueryBuildDataSource si
(queryBuildDataSource)
{
// borra el rango anterior y luego lo agrega
queryBuildDataSource.clearRanges(); if (!
queryBuildRange)
{
consultaBuildRange
=queryBuildDataSource.addRange
(fieldNum(CustTable, AccountNum));
[ 81 ]
Trabajar con formularios
}
queryBuildRange.value(rango);
}
}
}
}
contrato .setQuery(_consulta);
}
controlador.parmArgs(_args);
controlador.establecerRangos();
controlador.startOperation();
}
Servicio: Como mencioné anteriormente, no es una buena práctica mantener toda la lógica
comercial en una clase de controlador, porque sería una gran responsabilidad que una sola
clase la maneje. Por eso, aquí, hemos creado unServicioclase a la que se hace referencia en el
Controladorclase.
3. En el proyecto VS, cree una nueva clase llamadaControlador de saldo del clientecon el siguiente
fragmento de código:
[ 82 ]
Trabajar con formularios
;
// crea un nuevo objeto queryrun
queryRun = new queryRun
(_custBalanceDataContract.getQuery());
if(_custBalanceDataContract.parmTransDate()) saldo =
custTable.balanceMST
(fechaNula(),
_custBalanceDataContract.parmTransDate());
más
saldo = tablacliente.saldoMST(); // mostrar el
saldo
info(strFmt("%1 - %2",CustTable.AccountNum,saldo));
}
}
}
Aquí, obtenemos los parámetros del contrato y ejecutamos la lógica comercial. El saldo del cliente en
la moneda de contabilidad se muestra en una fecha si se especifica una fecha determinada. Aquí,
también podríamos multiproceso de nuestro proceso.
Constructor de interfaz de usuario: esta clase solo se requiere cuando desea jugar con
parámetros agregados (atributos de miembro de datos) en la clase de contrato. Por ejemplo,
modificar la búsqueda o habilitar/deshabilitar ciertos parámetros en un cuadro de diálogo.
CustBalanceDataContract custBalanceDataContract;
[ 83 ]
Trabajar con formularios
// o alternativamente
//
dialogFieldTransDate.enabled
(_checkBoxControl.checked()); devolver
verdadero;
}
;
súper();
}
}
Aquí, anulamos elpublicarmétodo y obtener los dos campos de diálogo. Yendo más allá,
registramos elpermitirModificarFechaModificado()en evento modificado de nuestro
dialogFieldAllowModifyDatecontrol.
Finalmente, necesitamos crear un elemento de menú de acción como punto de entrada para ejecutar el
código anterior:
[ 84 ]
Trabajar con formularios
[ 85 ]
Trabajar con formularios
[ 86 ]
Trabajar con formularios
En esta receta, crearemos una forma dinámica. Para mostrar cuán flexible puede ser el formulario,
replicaremos el diseño del formulario existenteGrupos de clientesformulario ubicado en elCuentas
por cobrarmódulo. El formulario Clientes se puede abrir navegando aCuentas por cobrar|
Configuración|Clientes.
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
clase CustGroupDynamicForm {
[ 87 ]
Trabajar con formularios
FormBuildGroupControl grpCuerpo;
argumentos argumentos;
FormularioEjecutar formularioEjecutar;
# Tarea
cmdNuevo =
btngrp1.addControl(FormControlType::CommandButton,
'NewButton'); cmdNuevo.primario(NoSí::Sí);
cmdNuevo.comando(#tareaNueva);
cmdDel =
btngrp1.addControl(FormControlType::CommandButton,
'DeleteButton'); cmdDel.text("Eliminar");
[ 88 ]
Trabajar con formularios
cmdDel.saveRecord(NoSí::Sí);
cmdDel.primary(NoSí::Sí);
cmdDel.command(#taskDeleteRecord);
mbPosting = btngrp2.addControl(FormControlType::MenuButton,
'MenuButtonPosting'); mbPosting.helpText("Configurar datos relacionados
para el grupo."); mbPosting.text("Configuración");
mibPosting =
mbPosting.addControl( FormControlType::MenuFunctionButton,
'Publicar'); mibPosting.text('Publicación de artículo');
mibPosting.saveRecord(NoSí::No);
mibPosting.dataSource(ds.id());
mibPosting.menuItemName
(menuitemDisplayStr(InventPosting));
mibForecast =
btngrp2.addControl(FormControlType::MenuFunctionButton,
'SalesForecast'); mibForecast.text('Pronóstico');
mibForecast.saveRecord(NoSí::No);
mibForecast.menuItemName(
menuitemDisplayStr(ForecastSalesGroup));
grpBody.heightMode(FormHeight::ColumnHeight);
grpCuerpo.columnspace(0);
grpBody.style(GroupStyle::BorderlessGridContainer);
grilla.addDataField
(ds.id(), fieldNum(CustGroup,CustGroup));
[ 89 ]
Trabajar con formularios
grilla.addDataField(
ds.id(), fieldNum(CustGroup,Name));
grilla.addDataField(
ds.id(), fieldNum(CustGroup,PaymTermId));
grilla.addDataField(
ds.id(), número de campo (grupo de clientes, período de compensación));
grilla.addDataField(
ds.id(), fieldNum(CustGroup,BankCustPaymIdTable));
grilla.addDataField(
ds.id(), fieldNum(CustGroup,TaxGroupId)); argumentos =
nuevos argumentos();
argumentos.objeto(formulario);
formRun = classFactory.formRunClass(args);
ejecutarformulario.init();
formularioEjecutar.ejecutar();
ejecutarformulario.separar();
}
[ 90 ]
Trabajar con formularios
Cómo funciona...
Comenzamos el código declarando variables. Tenga en cuenta que la mayoría de los tipos de variables comienzan con
Construir formulario,que forman parte de un conjunto de clases de aplicación utilizadas para crear formularios
dinámicos. Cada uno de estos tipos corresponde a los tipos de control que se utilizan manualmente al crear formularios
en el AOT.
[ 91 ]
Trabajar con formularios
El nombre deformaEl objeto no es importante, ya que se trata de una forma dinámica. El formulario debe
tener una fuente de datos, por lo que agregamos una llamando alañadirFuenteDeDatos()método a laforma
objeto y proporcionando un previamente creadodictTableobjeto, como se muestra aquí:
ds = formulario.addDataSource(dictTable.name());
ds.table(dictTable.id());
Cada formulario tiene un diseño, por lo que agregamos un nuevo diseño, definimos su estilo como una lista simple y establecemos su
títulofuente de datos, como se muestra en el siguiente fragmento de código:
diseño = formulario.addDesign('Diseño');
design.caption("Grupos de clientes");
diseño.estilo(FormStyle::SimpleList);
diseño.titleDatasource(ds.id());
Una vez que el diseño está listo, podemos comenzar a agregar controles desde el código como si lo
hiciéramos desde el AOT. Lo primero que debe hacer es agregar unbandapanel de acción con sus
botones:
actionPane = design.addControl(
(FormControlType::ActionPane, 'ActionPane');
actionPane.style(ActionPaneStyle::Strip); actionPaneTab =
actionPane.addControl(
(FormControlType::ActionPaneTab, 'ActionPaneTab'); btngrp1 =
actionPaneTab.addControl(
Inmediatamente después del panel de acción, agregamos una cuadrícula que se expande automáticamente y apunta a la
fuente de datos mencionada anteriormente. Solo para seguir las mejores prácticas, colocamos la cuadrícula dentro de un
Grupocontrol:
A continuación, agregamos una serie de controles de cuadrícula que apuntan a los campos de fuente de datos
relevantes llamandoañadir campo de datos ()sobre elcuadrículaobjeto. Lo último es inicializar y ejecutar el
formulario. Aquí, usamos el enfoque recomendado para crear y ejecutar formularios usando el disponible
globalmentefábrica de clasesobjeto.
[ 92 ]
Trabajar con formularios
En esta receta, para demostrar el uso de divisores, modificaremos uno de los formularios existentes
que no tiene divisor. vamos a modificar elReconciliación de la cuenta forma en elManejo de caja y
bancosmódulo. Puede abrir este módulo navegando aManejo de caja y bancos|Configuración|
grupo bancario. En la siguiente captura de pantalla, puede ver que no es posible controlar el
tamaño de cada cuadrícula individualmente y que se redimensionan automáticamente usando un
botón de opción fijo al cambiar el tamaño del formulario:
En esta receta, demostraremos el uso de divisores mejorando esta situación. Agregaremos un divisor de
formulario entre dos cuadrículas en el formulario mencionado. Esto permitirá a los usuarios definir los
tamaños de ambas cuadrículas para garantizar que los datos se muestren de manera óptima.
[ 93 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
Propiedad Valor
Nombre Parte superior
Declaración automática Sí
Tipo de marco Ninguna
Propiedad Valor
Parte superior Auto
Altura altura de la columna
Propiedad Valor
Nombre Disidente
Estilo DivisorVerticalContenedor
Declaración automática Sí
SysFormSplitter_Y formSplitter;
[ 94 ]
Trabajar con formularios
Cómo funciona...
Normalmente, se debe colocar un divisor entre dos grupos de formularios. En esta receta, para seguir esta regla,
necesitamos ajustar elBancoGrupodiseño del formulario. losDetallesEncabezadogrupo yPestaña
los controles se mueven a un nuevo grupo llamadoParte superior.No queremos que este nuevo grupo sea visible
para el usuario, por lo que configuramosTipo de marcoaNinguna.AjusteDeclaración automáticaaSíle permite
acceder a este objeto desde el código. Finalmente, hacemos que este grupo se expanda automáticamente en la
dirección horizontal configurando suAnchopropiedad aAncho de columna.En esta etapa, el diseño del formulario
visual no cambia, pero ahora tenemos listo el grupo superior.
[ 95 ]
Trabajar con formularios
En medio de estos dos grupos, agregamos un divisor. El divisor no es más que otro grupo
que parece un divisor. establecemos suEstilopropiedad a
SplitterVerticalContainer,lo que hace que este control parezca un divisor de forma adecuado.
De esta manera, se pueden agregar divisores horizontales a cualquier forma. También se pueden agregar divisores
verticales a los formularios utilizando un enfoque similar. Para esto, necesitamos usar otra clase de aplicación.
llamóSysFormSplitter_X.
Aunque no es la mejor práctica, a veces estos problemas se pueden resolver fácilmente haciendo que el
niño forme una ventana modal. En otras palabras, la segunda forma siempre permanece encima de la
primera hasta que se cierra. En esta receta, haremos una ventana modal desde elCrear orden de venta
forma.
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
Propiedad Valor
Tipo de ventana Surgir
[ 96 ]
Trabajar con formularios
[ 97 ]
Trabajar con formularios
Cómo funciona...
El diseño del formulario tiene unTipo de ventanapropiedad, que se establece enEstándarpor defecto. Para hacer que
un formulario se comporte como una ventana modal, tenemos que cambiarlo aSurgir.Dichos formularios siempre
permanecerán encima del formulario principal.
Hay más...
Ya sabemos que algunos de los formularios de Dynamics 365 for Finance and Operations se crean
dinámicamente usando elDiálogoclase. Si echamos un vistazo más profundo al código, encontraremos que
elDiálogoclass en realidad crea un formulario de tiempo de ejecución. Esto significa que podemos aplicar el
mismo principio: cambiar la forma relevantediseñopropiedad. Las siguientes líneas de código se pueden
agregar alDiálogoobjeto y hará el trabajo:
dialog.dialogForm().buildDesign().windowType
(FormWindowType::Popup);
Aquí, obtenemos una referencia al diseño del formulario usando primero elformulario de diálogo ()metodo de
laDiálogoobjeto para obtener una referencia alformulario de diálogoobjeto, y luego llamamos
construirDiseño()sobre este último objeto. Por último, configuramos eldiseñopropiedad llamando a su
tipoventana()método con elFormWindowType::Emergenteargumento.
Ver también
[ 98 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
actionPane = this.design().controlNum(1); if (!
actionPane ||
!(actionPane es FormActionPaneControl) || actionPane.style()
== ActionPaneStyle::Strip)
{
devolver;
}
actionPaneTab = actionPane.controlNum(1);
[ 99 ]
Trabajar con formularios
if (!actionPaneTab ||
!(actionPaneTab es FormActionPaneTabControl))
{
devolver;
}
btngrp = actionPaneTab.addControl
(FormControlType::ButtonGroup, 'ButtonGroup');
btngrp.caption("Acerca de");
cmdAbout = btngrp.addControl
(FormControlType::CommandButton, 'Acerca de');
cmdAcerca de.command(#tareaAcercade);
cmdAbout.imageUbicación
(UbicaciónSysImage::RecursoEmbedded);
cmdAcerca de.imagennormal('412');
cmdAbout.big(NoSí::Sí);
cmdAbout.saveRecord(NoSí::No);
}
4. Para probar los resultados, abra cualquier página de lista; por ejemplo, ir aCuentas por cobrar
|Clientes|todos los clientesy notará un nuevo botón llamadoAcerca de Dynamics 365 para
operacionesen elAcciónpanel, como se muestra en la siguiente captura de pantalla:
[ 100 ]
Trabajar con formularios
Cómo funciona...
losSysSetupFormRunes la clase de aplicación a la que llama el sistema cada vez que un usuario ejecuta un
formulario. El mejor lugar para agregar nuestro control personalizado es en sucorrer()método.
usamos eleste diseño()para obtener una referencia al diseño del formulario y luego verificamos si el
primer control en el diseño es un panel de acción. Continuamos agregando un nuevo grupo de
botones separado y elAcerca de Dynamics 365 para operacionesBotón de comando. Ahora, cada
formulario en Dynamics 365 for Finance and Operations con un panel de acción tendrá un botón
más.
[ 101 ]
Trabajar con formularios
En esta receta, demostraremos cómo guardar las últimas selecciones del usuario. Para hacerlo lo más
sencillo posible, utilizaremos los filtros existentes en laExtracto de cuentaformulario, que se puede abrir
navegando aManejo de caja y bancos|Común|cuentas bancarias, seleccionando cualquier cuenta
bancaria y luego haciendo clic en elReconciliación de la cuentabotón en el Accióncristal. Este formulario
contiene un control de filtro llamadoVista, que le permite visualizar extractos bancarios en función de su
estado. La vista predeterminada de este formulario esno reconciliado. Veremos cómo utilizar el siguiente
código para guardar las selecciones del usuario para propósitos futuros.
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
TodoNoReconciliado showTodoReconciliado;
# define.VersiónActual(1)
# localmacro.CurrentList
showAllReconciled
# endmacro
showAllReconciled = AllNotReconciled::NotReconciled;
}
interruptor (versión)
{
caso #VersiónActual:
[versión, #CurrentList] = _packedClass; devolver
verdadero;
defecto:
falso retorno;
}
[ 102 ]
Trabajar con formularios
falso retorno;
}
devuelve elemento.args().menuItemName();
}
devuelve este.nombre();
}
return UtilElementType::Form;
}
volver curUserId();
}
volver curaxt();
}
xSysLastValue::getLast(esto);
TodoReconciliado.selection(mostrarTodoReconciliado);
showAllReconciled = AllReconciled.selection();
xSysLastValue::saveLast(esto);
todoReconciliado.selección(1);
[ 103 ]
Trabajar con formularios
Cómo funciona...
Primero, definimos una variable que almacenará el valor del control de filtro. Los #Lista actual
macro se utiliza para definir una lista de variables que vamos a guardar en los datos de uso.
Actualmente, tenemos nuestra única variable dentro.
Los #Versión actualmacro define una versión de los valores guardados. En otras palabras, dice que
las variables definidas por el #Lista actualmacro, que se almacenará en los datos de uso del sistema,
se puede abordar usando el número1.
Normalmente, al implementar el último valor guardado por primera vez para un objeto en particular,
# Versión actualse establece en1.Más adelante, si decide agregar nuevos valores o cambiar los
existentes, debe cambiar el valor de #Versión actual,normalmente aumentándolo en uno. Esto
asegura que el sistema aborde la lista correcta de variables en el uso.
losinitParmDefault()El método especifica los valores predeterminados si no se encuentra nada en los datos de
uso. Normalmente, esto sucede si ejecutamos un formulario por primera vez, cambiamos
# Versión actual,o borramos los datos de uso. Este método es llamado automáticamente por el
xSysÚltimoValorclase.
[ 104 ]
Trabajar con formularios
loslastValueDesignName()El método está destinado a devolver el nombre del diseño actual del objeto en los
casos en que el objeto puede tener varios diseños. En esta receta, solo hay un diseño, así que en lugar de
dejarlo vacío, lo usamos para un propósito ligeramente diferente. El método devuelve el nombre del elemento
de menú utilizado para abrir este formulario. En este caso, se almacenarán conjuntos de datos de uso
separados para cada elemento de menú que abra el mismo formulario.
[ 105 ]
Trabajar con formularios
Esta receta discutirá los principios de cómo construir formularios basados en árboles. Como ejemplo,
utilizaremos elmodelo de presupuestoformulario, que se puede encontrar navegando apresupuesto|
Configuración| Presupuesto básico|Modelos de presupuesto. Este formulario contiene una lista de modelos
presupuestarios y sus submodelos y, aunque los datos se organizan mediante una estructura principal-
secundario, todavía se muestran como una cuadrícula. En esta receta, para demostrar el uso de laÁrbolcontrol,
reemplazaremos la rejilla con una nuevaÁrbolcontrol.
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
1. Agregue un nuevo proyecto en su solución en Visual Studio. Agregar una nueva clase llamada
PresupuestoModeloÁrbolcon el siguiente fragmento de código:
Árbol FormTreeControl;
PresupuestoModelId modelId;
}
[ 106 ]
Trabajar con formularios
árbol.select(elementoIdx);
}
mientras selecciona submodelo
donde submodel.ModelId == _modelId &&
submodel.Type == HeadingSub::SubModel {
this.createNode(
artículoIdx,
submodelo.SubModelId,
submodelo.RecId);
}
devolver itemIdx;
}
modelo BudgetModel;
submodelo BudgetModel;
TreeItemIdx itemIdx;
árbol.borrarTodo();
árbol.bloqueo();
mientras selecciona RecId, ModelId del modelo
donde model.Type == HeadingSub::Heading
notExists unirse al submodelo
donde submodelo.SubModelId == modelo.ModelId &&
submodelo.Tipo == EncabezadoSub::SubModelo
{
itemIdx =
this.createNode(FormTreeAdd::Root,
modelo.ModelId,
modelo.RecId);
SysFormTreeControl::expandTree(árbol, itemIdx);
}
árbol.desbloquear(verdadero);
}
[ 107 ]
Trabajar con formularios
Propiedad Valor
Visible No
Propiedad Valor
Nombre Árbol
BudgetModelTree modelTree;
5. Agregue las siguientes líneas de código en la parte inferior del formularioen eso()método:
modelTree = BudgetModelTree::construct(Tree);
árbolmodelo.construirÁrbol();
[ 108 ]
Trabajar con formularios
si (_nuevoElemento.datos())
{
selecciona primero Solo modelo
donde modelo.RecId == _newItem.data();
if (modelo.Tipo == HeadingSub::SubModelo) {
modeloId = modelo.SubModelId;
selecciona primero Solo modelo
donde modelo.ModelId == modelId
&& modelo.Tipo == Subtítulo::Título;
}
BudgetModel_ds.findRecord(modelo);
PresupuestoModelo_ds.refresh();
}
si (BudgetModel.RecId)
{
árbolmodelo.construirÁrbol();
}
}
árbolmodelo.construirÁrbol();
si (SubModelo.RecId)
{
árbolmodelo.construirÁrbol();
}
}
[ 109 ]
Trabajar con formularios
árbolmodelo.construirÁrbol();
[ 110 ]
Trabajar con formularios
Cómo funciona...
Esta receta contiene mucho código, por lo que creamos una clase para contener la mayor parte. Esto le permite
reutilizar el código y mantener el formulario menos desordenado.
El primer método escrearNodo()y se utiliza para crear un solo nodo de modelo de presupuesto con
sus hijos, si los hay. Es un método recursivo y se llama a sí mismo para generar los hijos del nodo
actual. Acepta un nodo principal y un modelo de presupuesto como argumentos. En este método,
creamos el nodo llamando alañadirÁrbolItem()metodo de laSysFormTreeControlclase. El resto del
código recorre todos los submodelos y crea subnodos (si los hay) para cada uno de ellos.
[ 111 ]
Trabajar con formularios
El resto del código en el formulario es para garantizar que el árbol se reconstruya siempre que se modifiquen los
datos.
Ver también
Debido a la integridad de la estructura de datos, laVer detallesfunción funciona la mayor parte del tiempo. Sin
embargo, cuando se trata de relaciones de tablas complejas, no funciona correctamente o no funciona en
absoluto. Otro ejemplo de cuando esta característica no funciona automáticamente es cuando el
monitoroeditarLos métodos se utilizan en un formulario. En estos y muchos otros casos, elVer detalles
La función debe implementarse manualmente.
En esta receta, para demostrar cómo funciona, modificaremos elDiario generalforma en el Libro
mayormódulo y agregue elVer detallescaracterística a laDescripcióncontrol, lo que permite a los
usuarios saltar del menú contextual del botón derecho alnombres de revistasforma.
[ 112 ]
Trabajar con formularios
Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:
MenúFunción mf;
nombre = LedgerJournalName::find
(LedgerJournalTable.JournalName);
si (!nombre)
{
devolver;
}
mf = new MenuFunction
(menuitemDisplayStr(LedgerJournalSetup),
MenuItemType::Display);
mf.run(argumentos);
}
[ 113 ]
Trabajar con formularios
Es posible que deba actualizar su página de Dynamics 365 for Operations para reflejar sus
cambios en la interfaz.
[ 114 ]
Trabajar con formularios
Cómo funciona...
Normalmente, elVer detallesLa función está controlada por las relaciones entre las tablas
subyacentes. Si no hay relaciones o el control de formulario no está vinculado a un campo de
tabla, esta opción no está disponible. Sin embargo, podemos forzar que aparezca esta opción
anulando el controlsaltoRef()método.
En este método, agregamos código que abre el formulario correspondiente. Esto se puede hacer declarando,
instanciando y ejecutando unFormularioEjecutarobjeto, pero una forma más fácil de hacer esto es simplemente
ejecutar el elemento de menú relevante desde el código. En esta receta, el código ensaltoRef()hace exactamente eso.
En el código, primero verificamos si se encuentra un registro de nombre de diario válido. Si es así, ejecutamos el
Configuración del libro mayorelemento de menú con unargumentosobjeto que contiene el registro de nombre de diario
y el actualformainformación del objeto como llamante. El resto lo hace automáticamente el sistema, es decir, elnombres
de revistasse abre el formulario con el nombre de la revista seleccionada actualmente.
[ 115 ]
Trabajar con formularios
Los patrones de formulario han facilitado el desarrollo de formularios en Dynamics 365 for Finance and Operations al
proporcionar una experiencia guiada para aplicar patrones a formularios para garantizar que sean correctos y
coherentes. Los patrones ayudan a validar las estructuras de formularios y controles, y también el uso de controles en
algunos lugares. Los patrones también ayudan a garantizar que cada nueva forma que encuentra un usuario sea
inmediatamente reconocible en apariencia y función. Los patrones de formulario pueden proporcionar muchas
propiedades de control predeterminadas, y estas también contribuyen a una experiencia de desarrollo más guiada. Dado
que los patrones proporcionan muchas propiedades de diseño predeterminadas, ayudan a garantizar que los
formularios tengan un diseño receptivo. Finalmente, los patrones también ayudan a garantizar una mejor compatibilidad
con las actualizaciones.
Muchos de los estilos y plantillas de formulario existentes de AX 2012 siguen siendo compatibles con la
versión actual de Dynamics 365 for Finance and Operations. Sin embargo, las plantillas y los estilos de
formulario heredados que no son compatibles tienen una ruta de migración a un patrón de Dynamics 365
for Finance and Operations. Debido a que los elementos fundamentales de Dynamics 365 for Finance and
Operations se crean en base a esos patrones y estilos de formulario heredados, la transición de AX 2012 a
la versión actual de Dynamics 365 for Finance and Operations es lo más fácil posible.
Cómo hacerlo
La aplicación de un patrón es un proceso sencillo que puede modificar propiedades en varios
contenedores y controles en un formulario. Este es el flujo estándar para aplicar patrones:
[ 116 ]
Trabajar con formularios
2. Decide qué patrón aplicar. Puede consultar el archivo de detalles exportado en la última
receta.
3. Ahora necesitamos aplicar el patrón. Haga clic derecho en elNodo de diseñodel formulario de
destino, seleccioneAplicar patróny luego haga clic en elPatrón a aplicar.
4. Como último paso, es posible que debamos manejar algunos errores. La información sobre el patrón aparece en la
Patrónpestaña. Para obtener información sobre la estructura del patrón, haga clic ennombres de controlsobre el
Patrónpestaña para navegar por la estructura del patrón.
5. Haga doble clic en un error para ir al control para el que se informó el error, si existe el
control.
6. Si el control ya existe en el formulario pero está en un lugar diferente, mueva
el control al lugar correcto, como lo indica el patrón.
7. Si el control no existe, cree el control.
Maestro de detalles
cuadros de datos
Tabla de contenido
Espacios de trabajo operativos
Para obtener una lista completa de los formularios que actualmente usan un patrón de formulario en particular,
genere el Patrones de formularioinforme desde dentro de Microsoft Visual Studio. En el menú de Dynamics 365,
expanda elComplementosopción y haga clic enEjecutar formularioinforme de patrones Un proceso en segundo
plano genera el informe. Después de varios segundos, aparece un cuadro de mensaje en Visual Studio para indicar
que se ha generado el informe y le informa sobre la ubicación delPatrones de formularioarchivo de informe. Puede
filtrar este archivo por patrón para encontrar formularios que utilicen un patrón en particular.
[ 117 ]
Trabajar con formularios
Cómo hacerlo...
Vamos a ver cómo ejecutar el informe de patrones de formulario. Este informe se genera a través de Visual
Studio y nos brinda información sobre todos los formularios en el sistema con los patrones de formulario
correspondientes:
[ 118 ]
Trabajar con formularios
4. Abra el archivo de Excel y notará que tenemos columnas que nos dicen en qué modelo se encuentra
el formulario, el nombre del sistema para el formulario, así como el estilo y el patrón del
formulario:
[ 119 ]
Trabajar con formularios
5. En este archivo CSV, también obtendremos detalles sobre los controles y el porcentaje de cobertura. El
filtro ayuda a determinar qué formulario del sistema tiene qué patrón aplicado y también qué
formularios no tienen ningún patrón aplicado. Los siguientes son todos los patrones de formulario
en Dynamics 365 for Operations:
[ 120 ]
Trabajar con formularios
En esta receta, crearemos un formulario simple usando una plantilla y agregaremos este formulario a uno de los menús
para que los usuarios puedan acceder a él desde la interfaz.
preparándose
Pensemos en un escenario en el que el administrador necesita verificar todos los usuarios existentes en el sistema.
Aunque tenemos un formulario estándar para esto, no podemos dar acceso a todos porque este formulario también
tiene muchas otras opciones para realizar en este formulario, mientras que nuestro requisito es solo ver datos de solo
lectura. Usaremos este formulario en otras recetas para justificar el nombre de este formulario. Aquí, mostrará todos los
usuarios habilitados y deshabilitados.
Cómo hacerlo...
1. Agregue un nuevo formulario en su proyecto, asígnele el nombrePktDisabledUsers.
[ 121 ]
Trabajar con formularios
5. Tienes que agregar todos esos elementos en el diseño de la sección en el mismo orden.
[ 122 ]
Trabajar con formularios
6. Agregue todos los objetos que faltan, comoPanel de acciones, Grupo,y unCuadrícula.
7. Ahora, tienes que seleccionar un patrón paraFiltro personalizadogrupo; SeleccioneDisfrazy
Filtros rápidos.
8. Verá otro patrón disponible para esto; agregue todos los objetos faltantes a este
grupo:
[ 123 ]
Trabajar con formularios
10. Ahora, agreguemos algunos campos en su cuadrícula para mostrar datos reales. Agregar campos de Fuente de datos
de información de usuario:
12. Ahora, para agregar este formulario al front-end, cree unElemento del menú de visualizaciónpara este formulario.
[ 124 ]
Trabajar con formularios
13. Crea una extensión deAdministración del sistemamenú y agregue este nuevo elemento de menú de
visualización enusuarios,como en la siguiente captura de pantalla:
14. Para probar este formulario, guarde todos los cambios y cree la solución. Ahora, ve a Administrador del
sistema| Usuarios|Usuarios discapacitados con color. Su formulario debe verse como la siguiente
captura de pantalla:
[ 125 ]
Trabajar con formularios
Cómo funciona...
Crear un nuevo formulario en Dynamics 365 for Finance and Operations es muy sistemático y fácil. Todo lo
que necesita hacer es identificar el propósito del formulario y elegir un patrón relevante. Una vez que
aplique un patrón a su formulario, mostrará los detalles del objeto requerido con una secuencia, como se
muestra en el paso 4 de la receta anterior. Todo lo que necesita agregar ahora son los objetos respectivos
en su diseño con la secuencia dada.
[ 126 ]