Download as pdf or txt
Download as pdf or txt
You are on page 1of 64

Traducido del inglés al español - www.onlinedoctranslator.

com

Trabajar con formularios


2
En este capítulo, cubriremos las siguientes recetas:

Creación de diálogos usando el marco RunBase


Manejo del evento de diálogo
Creación de cuadros de diálogo utilizando el marco SysOperation

Creación de un formulario dinámico

Agregar un divisor de formulario

Crear un formulario modal

Modificar múltiples formularios dinámicamente

Almacenar los valores del último formulario

Uso de un control de árbol Adición del

vínculo Ver detalles Selección de un patrón

de formulario Lista completa de patrones de

formulario Creación de un nuevo formulario

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.

Creación de cuadros de diálogo utilizando el


marco RunBase
Los diálogos son una forma de presentar a los usuarios un formulario de entrada simple. Suelen usarse para
pequeñas tareas de usuario, como completar valores de informes, ejecutar trabajos por lotes y presentar solo los
campos más importantes al usuario al crear un nuevo registro. Los diálogos normalmente se crean a partir de
código X++ sin almacenar el diseño real en el AOT.

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:

1. Agregar un nuevo proyectoCrear diálogo.


2. Agregar un nuevoEjecutableclase y cambiarle el nombreMiDiálogo.Ahora, agregue el siguiente
fragmento de código:

Declare todos sus objetos en la clase, como se muestra a continuación:

clase MyDialog extiende RunBase {

campo de diálogo campoCuenta;


campo de diálogo nombre del campo;
campo de diálogo grupocampo;
campo de diálogo campoMoneda;
campo de diálogo fieldPaymTermId;
campo de diálogo campoModoPago;
nombre del cliente nombrecliente;
ID de grupo de clientes idGrupocliente;
Código de moneda código de moneda;
ClientePaymTermId paymTermId;
CustPaymMode paymMode;

paquete de contenedor público ()


{
volver conNull();
}

desempaquetado booleano público (contenedor _packedClass) {

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();

dialog.caption("Información del cliente");

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:

booleano público getFromDialog() {

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();

Utilizar elcorrermétodo para hacer declaraciones de Infolog, como en el siguiente código:

ejecución de vacío público ()


{
info("Ha ingresado la información del cliente:");
info(strFmt("Cuenta: %1", custAccount)); info(strFmt("Nombre:
%1", nombrecliente));
info(strFmt("Grupo: %1", custGroupId)); info(strFmt("Moneda: %1",
codigomoneda)); info(strFmt("Condiciones de pago: %1",
paymTermId)); info(strFmt("Método de pago: %1", paymMode));

[ 66 ]
Trabajar con formularios

public static void main(Args _args) {

Mi diálogo miDiálogo = new MiDiálogo();

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.

lospaquete()ydeshacer()Los métodos se utilizan normalmente para convertir un objeto en un contenedor y


convertir el contenedor nuevamente en un objeto, respectivamente. Un contenedor es un formato común
utilizado para almacenar objetos en la memoria caché del usuario (Último valor del sistema)o para transferir el
objeto entre los niveles de servidor y cliente. losEjecutarBaseframework necesita que estos dos métodos sean
implementados en todas sus subclases. En este ejemplo, no estamos usando ninguno de lospaquete()o
deshacer()características, pero debido a que estos métodos son obligatorios, devolvemos un
contenedor vacío depaquete()y volvemosverdaderodedeshacer().

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.

Los controles de diálogo adicionales se agregan al diálogo usando elañadirCampo(), añadirGrupo(), y


añadirPáginaTab()métodos. Hay más métodos, comoagregarTexto(), agregarImagen(), yagregarMenuItemButton(),que
se utilizan para agregar diferentes tipos de controles. Todos los controles deben agregarse directamente al
objeto de diálogo. Agregar un control de entrada a grupos o pestañas se realiza llamandoAgregue campo()justo
después deañadir grupo()oagregarPáginaTab().En el ejemplo anterior, agregamos páginas de pestañas, grupos y
campos en una secuencia lógica de arriba hacia abajo. Tenga en cuenta que es suficiente solo agregar una
segunda página de pestañas; la primera pestaña, etiquetadaGeneral,es añadido automáticamente por el
EjecutarBaseestructura.

[ 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.

Manejo del evento de diálogo


A veces, en la interfaz de usuario, es necesario cambiar el estado de un campo según el estado de
otro campo. Por ejemplo, si el usuario marca elMostrar filtrocasilla de verificación, luego otro
campo,Filtrar, aparece o se habilita. En formularios AOT, esto se puede hacer usando el
modificado()evento de control de entrada. Sin embargo, si se requiere esta función en los cuadros de diálogo de tiempo de
ejecución, el manejo de eventos no es tan sencillo.

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:

clase MyDialogSelect extiende RunBase {

DialogField campoCuenta;
Nombre de campo de DialogField;
Grupo de campos DialogField;
DialogField campo Moneda;
DialogField fieldPaymTermId;
DialogField fieldPaymMode;

paquete contenedor público() {

volver conNull();
}

desempaquetado booleano público (contenedor _packedClass) {

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();

dialog.caption("Información del cliente");


dialog.allowUpdateOnSelectCtrl(verdadero);

campoCuenta = dialog.addField
(extendedTypeStr(CustAccount),"Cuenta de cliente");

nombre del campo=dialog.addField


(extendedTypeStr(CustName));
fieldName.habilitado (falso);

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;
}

diálogo vacío públicoSelectCtrl() {

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);
}

public static void main(Args _args) {

MyDialogSelect myDialogSelect = new MyDialogSelect();

if (miDialogSelect.prompt()) {

myDialogSelect.run();
}
}

[ 72 ]
Trabajar con formularios

3. Establecer esta clase comoEstablecer como objeto de inicio

[ 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.

En eldiálogo()método miembro, llamamos alpermitirActualizarEnSeleccionarCtrl()método con elverdadero


argumento para habilitar el manejo de eventos de control de entrada. También deshabilitamos todos los
controles, aparte deCuenta de cliente,llamandohabilitar()con elfalsoparámetro para cada control.

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.

losprincipal()El método asegura que la clase es ejecutable.

Ver también

losCreación de cuadros de diálogo utilizando el marco RunBasereceta

Creación de cuadros de diálogo utilizando el marco


SysOperation
SysOperation es un marco en Dynamics 365 for Finance and Operations que permite que la lógica de la
aplicación se escriba de una manera que admita la ejecución de operaciones de forma interactiva o a través
del servidor por lotes D365. El marco SysOperation sigue elMVC(Modelo-Vista-Controlador) patrón. Como
su nombre lo indica, el patrón MVC aísla los componentes del modelo, la vista y el controlador, lo que hace
que el proceso se acople libremente sobre el marco SysOperation. Dependiendo de los parámetros, el
controlador puede ejecutar diferentes operaciones de servicio bajo cuatro modos de ejecución principales.
Independientemente del modo en que se ejecute un servicio, el código se ejecuta en un servidor. Esto hace
que el número mínimo de viajes de ida y vuelta entre el servidor y el cliente.

Sincrónico: cuando un servicio se ejecuta en modo síncrono, aunque se ejecuta en un servidor,


congela el cliente del navegador de Dynamics 365 for Operations. Se inicia una llamada desde el
cliente y se calcula un objeto en el servidor para ejecutarlo en CIL. Esto es bueno para procesos más
pequeños.

[ 76 ]
Trabajar con formularios

Asincrónico: En una llamada de servicio asincrónica, el cliente sigue respondiendo. Solo


funcionan con el mecanismo de llamada de servicio asíncrono de WCF. Por eso es
necesario que funcione como un servicio AIF. Se debe soltar en el grupo de servicios de
Dynamics 365 for Operations y volver a implementar el grupo de servicios. Esto es bueno
para procesos largos donde la durabilidad no es importante.
Asíncrono Confiable: Funciona como un servicio por lotes. Tan pronto como se inicia una llamada
para ejecutar un servicio en modo asíncrono confiable, se programa para ejecutarse en el servidor
por lotes al instante, pero se elimina tan pronto como finaliza el trabajo. Uno puede verlo entre
otros trabajos programados. Dado que se ejecuta en un servidor por lotes, puede aprovechar el
poder del procesamiento paralelo. Se usa en escenarios donde un trabajo debe ejecutarse en un
servidor y no programarse. Hay espacio para la mejora del rendimiento haciendo uso del
procesamiento paralelo entre diferentes AOS.
Lote programado: un trabajo está programado para ejecutarse en un servidor por lotes. Esto es
similar a asincrónico confiable, excepto que no elimina la instancia de trabajo una vez que finaliza
el trabajo. Esto se usa para trabajos que deben ejecutarse repetidamente en intervalos de tiempo
específicos. Hay espacio para mejoras de rendimiento haciendo uso del procesamiento paralelo
entre diferentes AOS.

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:

1. En el proyecto VS, cree una nueva clase llamadaClienteSaldoDatosContratocon el siguiente


fragmento de código:

[
Atributo de contrato de datos,
SysOperationContractProcessingAttribute
(classStr(CustBalanceUIBuilder)),
SysOperationGroupAttribute
('Fecha',"@ApplicationPlatform:SingleSpace", '1') ]

clase CustBalanceDataContract implementaSysOperationValidatable {

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) {

allowModifyDate = _allowModifyDate; return


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 () {

booleano ret = verdadero;

if(!transDate && allowModifyDate)


ret = checkFailed('La fecha de la transacción no puede estar vacía');

volver ret;
}

[Atributo de miembro de datos,


AifQueryTypeAttribute
('_packedQuery', cadena de consulta(CustTableSRS))
]
public str parmQuery(str _packedQuery = packedQuery) {

empaquetadoQuery = _packedQuery;
volver empaquetadoQuery;

[ 79 ]
Trabajar con formularios

Consulta pública getQuery() {

volver nuevo
Consulta(SysOperationHelper::base64Decode(packedQuery));
}

public void setQuery(Consulta _consulta) {

consulta empaquetada

=SysOperationHelper::base64Encode(_query.pack());
}

Aquí,SysOperationGroupAttributeespecifica cómo agrupamos los parámetros del


contrato y proporciona el orden en el que mostrar el grupo. El contrato de
datos también implementa elSysOperationValidatableinterfaz, por lo que
necesitamos anular laValidar()método y validar parámetros antes de real
comienza la ejecución. UsandoSysOperationContractProcessingAttribute,nosotros
especifica elconstructor de interfaz de usuarioclass para modificar el comportamiento del parámetro en tiempo de ejecución. Crearemos esta

clase de constructor de interfaz de usuario más adelante en este capítulo.

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.

clase CustBalanceController se extiende


SysOperationServiceController
{
str empaquetadaConsulta;
contrato CustBalanceDataContract;

/// <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 () {

QueryBuildRange rango de compilación de consulta;

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());

if (_consulta && custTableDS)


{
// rango de construcción
for (custTable = custTableDS.getFirst(true) ?
custTableDS.getFirst(true): custTableDS.cursor(); custTable;

custTable = custTableDS.getNext()) {

rango = rango == '' ? custTable.AccountNum : rango

+ ',' + 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);
}

public static void main(Args _args) {

Controlador de saldo del clientecontrolador = nuevo


CustBalanceController(classStr(CustBalanceService),
methodStr(CustBalanceService,processData),
SysOperationExecutionMode::Synchronous);

controlador.parmArgs(_args);
controlador.establecerRangos();
controlador.startOperation();
}

Aquí, ampliamos laSysOperationServiceControllerclass para heredar las capacidades del controlador. El


método principal se utiliza para crear una instancia de la clase de controlador, donde especificamos la
clase de servicio y el método de servicio que deben llamarse para ejecutar la lógica empresarial. los
establecerRangos()Se llama al método para especificar rangos basados en la persona que llama.

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:

clase Servicio de Saldo Cliente {

[Atributo de punto de entrada del sistema]


public void processData(CustBalanceDataContract
_custBalanceDataContract)
{
ConsultaEjecutar consultaEjecutar;
CustTable custTable;
Monto balance;

[ 82 ]
Trabajar con formularios

;
// crea un nuevo objeto queryrun
queryRun = new queryRun
(_custBalanceDataContract.getQuery());

// repite todos los resultados de la consulta


while(queryRun.next())
{
custTable = queryRun.get(tableNum(custTable));

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.

4. En el proyecto VS, cree una nueva clase llamadaCustBalanceUIBuildercon el siguiente


fragmento de código:

clase CustBalanceUIBuilder extiende


SysOperationAutomaticUIBuilder {

campo de diálogo dialogFieldAllowModifyDate; campo


campo de diálogo de diálogoTransDate;

CustBalanceDataContract custBalanceDataContract;

booleano público allowModifyDateModified(FormCheckBoxControl


_checkBoxControl)
{
// configurar habilitado o deshabilitado según la casilla de
verificación dialogFieldTransDate.enabled
(any2enum(dialogFieldAllowModifyDate.value()));

[ 83 ]
Trabajar con formularios

// o alternativamente
//
dialogFieldTransDate.enabled
(_checkBoxControl.checked()); devolver
verdadero;
}

public void postBuild() {

;
súper();

// obtener contrato de datos


custBalanceDataContract = this.dataContractObject();

// obtener campos de diálogo


dialogFieldTransDate= this.bindInfo().getDialogField
(custBalanceDataContract,methodstr
(clienteBalanceDataContract,parmTransDate));
dialogFieldAllowModifyDate=
this.bindInfo().getDialogField (custBalanceDataContract,
methodstr (custBalanceDataContract,parmAllowModifyDate));

// registrar métodos de anulación


dialogFieldAllowModifyDate.registerOverrideMethod
(methodstr(FormCheckBoxControl, modificado),
methodstr(CustBalanceUIBuilder,
allowModifyDateModified), esto); dialogFieldTransDate.enabled
(any2enum(dialogFieldAllowModifyDate.value()));

}
}

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

1. En el proyecto VS, cree un nuevo elemento de menú de acción llamado


Controlador de saldo del clientecon las siguientes propiedades:

2. Coloque el elemento del menú enCuentas por cobrar|Clientes|Todos los clientes|


Cliente|Balance|Mostrar saldo,como se muestra en la siguiente captura de pantalla:

[ 85 ]
Trabajar con formularios

3. Finalmente, nuestro formulario de cliente quedará de la siguiente manera:

4. El resultado final se verá de la siguiente manera:

[ 86 ]
Trabajar con formularios

Construyendo una forma dinámica


Un enfoque estándar para crear formularios en Dynamics 365 for Finance and Operations es crear y almacenar
formaobjetos en el AOT. Es posible lograr un alto nivel de complejidad utilizando este enfoque. Sin embargo, en
varios casos, es necesario tener formularios creados dinámicamente. En una aplicación estándar de Dynamics
365 for Finance and Operations, podemos ver que los objetos de la aplicación, como elNavegador de tablas
formulario, varias búsquedas o cuadros de diálogo se construyen dinámicamente. Incluso en Dynamics 365 for
Finance and Operations, donde tenemos una interfaz basada en navegador, cada formulario o cuadro de
diálogo se abre solo en un navegador.

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:

1. En el AOT, cree una nueva clase llamadaCustGroupDynamicFormcon el siguiente


fragmento de código.
2. Ejecutaremos esta clase directamente para obtener resultados. Entonces, solo por comodidad, escribiremos
todo el código en el método principal de esta clase:

clase CustGroupDynamicForm {

público vacío estático principal (Args _args)


{
// Declaraciones de objetos
DictTable tabladict;
Forma forma;
FormaConstruirDiseño diseño;
FormBuildDataSourceFormBuildDataSource ds;
FormBuildActionPaneControl panel de acción;
FormBuildActionPaneTabControl actionPaneTab;
FormBuildButtonGroupControl btngrp1;
FormBuildButtonGroupControl btngrp2;
FormBuildCommandButtonControl cmdNuevo;
FormBuildCommandButtonControl cmdDel;
FormBuildMenuButtonControl mbPublicación;
FormBuildFunctionButtonControl publicación mib;
FormBuildFunctionButtonControl mibPronóstico;
FormBuildGridControl cuadrícula;

[ 87 ]
Trabajar con formularios

FormBuildGroupControl grpCuerpo;
argumentos argumentos;

FormularioEjecutar formularioEjecutar;

# Tarea

dictTable = new DictTable(tableNum(CustGroup));

// Usa la clase Form para crear un formulario dinámico y // usa su


método para establecer diferentes propiedades. formulario = nuevo
formulario ();
form.name("CustGroupDynamic");

// Agregar fuente de datos en el formulario


ds = formulario.addDataSource(dictTable.name());
ds.table(dictTable.id());

//Establecer propiedades de diseño


diseño = formulario.addDesign('Diseño');
design.caption("Grupos de clientes");
diseño.estilo(FormStyle::SimpleList);
diseño.titleDatasource(ds.id());

//Añadir controles de diseño ActionPan y configurar sus //


propiedades
actionPane = design.addControl(FormControlType::ActionPane,
'ActionPane'); actionPane.style(ActionPaneStyle::Strip);
actionPaneTab =
actionPane.addControl( FormControlType::ActionPaneTab,
'ActionPaneTab'); btngrp1 = actionPaneTab.addControl(

FormControlType::ButtonGroup, 'NewDeleteGroup'); btngrp2 =


actionPaneTab.addControl(
FormControlType::ButtonGroup, 'ButtonGroup');

//Añadir controles de diseño CommandButton y configurar sus //


propiedades

cmdNuevo =
btngrp1.addControl(FormControlType::CommandButton,
'NewButton'); cmdNuevo.primario(NoSí::Sí);
cmdNuevo.comando(#tareaNueva);

//Añadir controles de diseño CommandButton y configurar sus //


propiedades

cmdDel =
btngrp1.addControl(FormControlType::CommandButton,
'DeleteButton'); cmdDel.text("Eliminar");

[ 88 ]
Trabajar con formularios

cmdDel.saveRecord(NoSí::Sí);
cmdDel.primary(NoSí::Sí);
cmdDel.command(#taskDeleteRecord);

//Agregar controles de diseño de MenuButton y configurar sus //


propiedades

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));

//Agregue controles de diseño de cuadrícula y configure


sus //propiedades

grpBody = design.addControl(FormControlType::Group, 'Body');

grpBody.heightMode(FormHeight::ColumnHeight);
grpCuerpo.columnspace(0);
grpBody.style(GroupStyle::BorderlessGridContainer);

grid = grpBody.addControl(FormControlType::Grid, "Grid");


grid.dataSource(ds.nombre());
grid.showRowLabels(falso);
grid.widthMode(FormWidth::ColumnWidth);
grid.heightMode(FormHeight::ColumnHeight);

//Agregue campos en Grid y configure sus //propiedades

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();
}

3. Para probar el formulario, ejecute elClienteGrupoDinámicoclase. Observe que el formulario es


similar al que se encuentra enCuentas por cobrar, que se puede obtener navegando a
Configuración|Clientes|Grupos de clientes, como se muestra en la siguiente captura de
pantalla:

[ 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.

Inmediatamente después de la declaración de la variable, creamos undictTableobjeto basado en elgrupocliente


mesa. Usaremos este objeto varias veces más adelante en el código. Luego, creamos unformaobjeto y
establezca un nombre llamando a las siguientes líneas de código:

formulario = nuevo formulario ();


form.name("CustGroupDynamic");

[ 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:

grpBody = design.addControl(FormControlType::Group, 'Body');


grpBody.heightMode(FormHeight::ColumnHeight);
grpCuerpo.columnspace(0);
grpBody.style(GroupStyle::BorderlessGridContainer);

grid = grpBody.addControl(FormControlType::Grid, "Grid");


grid.dataSource(ds.nombre());
grid.showRowLabels(falso);
grid.widthMode(FormWidth::ColumnWidth);
grid.heightMode(FormHeight::ColumnHeight);

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

Agregar un divisor de formulario


En Dynamics 365 for Finance and Operations, los formularios complejos constan de una o más secciones. Cada
sección puede contener grillas, grupos o cualquier otro elemento. Para mantener el tamaño de las secciones
mientras cambia el tamaño del formulario, las secciones normalmente están separadas por los llamados
divisores. Los divisores no son controles especiales de Dynamics 365 for Finance and Operations; estánGrupo
controles con sus propiedades modificadas para que parezcan divisores. La mayoría de los formularios de varias
secciones en Dynamics 365 for Finance and Operations ya contienen divisores.

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:

1. Agrega elBancoGrupoformulario en el AOT y, en el diseño del formulario, agregue un nuevoGrupo


controlar justo después de laPanel de accionescontrol con las siguientes propiedades:

Propiedad Valor
Nombre Parte superior

Declaración automática Sí
Tipo de marco Ninguna

2. Mueva elDetallesEncabezadoyPestañacontroles en el grupo recién creado.


3. Cambie las siguientes propiedades de la existenteDetallesEncabezadogrupo:

Propiedad Valor
Parte superior Auto
Altura altura de la columna

4. Agrega un nuevoGrupocontrol inmediatamente debajo delParte superiorgrupo con las siguientes


propiedades:

Propiedad Valor
Nombre Disidente

Estilo DivisorVerticalContenedor

Declaración automática Sí

5. Agregue la siguiente línea de código al final de la declaración de clase del formulario:

SysFormSplitter_Y formSplitter;

6. Agregue la siguiente línea de código en la parte inferior del formularioen eso()método:

formSplitter = new SysFormSplitter_Y(Splitter, Top, elemento);

[ 94 ]
Trabajar con formularios

7. Guarde todo su código y cree la solución.


8. Ahora, para probar los resultados, navegue hastaManejo de caja y bancos| Configuración|Grupos de
bancos. Tenga en cuenta que, ahora, el formulario tiene un divisor en el medio, lo que hace que el
formulario se vea mejor y le permite cambiar el tamaño de ambas cuadrículas, como se muestra en la
siguiente captura de pantalla:

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.

Cambiamos suParte superiorcomportamiento aAutoy hacerlo completamente expansible en la dirección vertical.


losAlturaLa propiedad de la cuadrícula dentro de este grupo también debe cambiarse aaltura de la columnapara
llenar todo el espacio vertical.

[ 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.

Finalmente, tenemos que declarar e inicializar elSysFormSplitter_Yclase de aplicación, que hace


el resto de las tareas.

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.

Crear un formulario modal


A menudo, las personas que no están familiarizadas con las computadoras y el software tienden a
perderse entre las ventanas de aplicaciones abiertas. Lo mismo se puede aplicar a Dynamics 365 for
Finance and Operations. Con frecuencia, un usuario abre un formulario, hace clic en un botón para abrir
otro y luego vuelve al primero sin cerrar el segundo formulario. A veces esto sucede intencionalmente, a
veces no, pero el resultado es que el segundo formulario se oculta detrás del primero y el usuario
comienza a preguntarse por qué no es posible cerrar o editar el primer formulario.

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:

1. Agrega elVentasCrearPedidoformulario en el proyecto y establecer suDiseñopropiedad:

Propiedad Valor
Tipo de ventana Surgir

[ 96 ]
Trabajar con formularios

2. Para probarlo, navegue hastaVentas y marketing|Común|Ordenes de venta| Todos los pedidos de


ventay empezar a crear un nuevo pedido. Note que, ahora, elcreación de órdenes de ventael formulario
siempre permanece en la parte superior:

[ 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

losCreación de cuadros de diálogo utilizando el marco RunBasereceta

Modificar múltiples formularios dinámicamente


En Dynamics 365 for Finance and Operations estándar, hay una clase llamada
SysSetupFormRun.La clase se llama durante la ejecución de cada formulario en Dynamics 365 for Operations;
por lo tanto, se puede usar para anular uno de los comportamientos comunes para todos los formularios de
Dynamics 365 for Finance and Operations. Por ejemplo, se pueden configurar diferentes colores de fondo de
formulario para diferentes cuentas de la empresa, se pueden ocultar o agregar algunos controles según las
circunstancias específicas, etc.

En esta receta, vamos a modificar elSysSetupFormRunclase para agregar automáticamente elAcerca de


Dynamics 365 para operacionesbotón para cada formulario en Dynamics 365 for Finance and
Operations.

[ 98 ]
Trabajar con formularios

Cómo hacerlo...
Realiza los siguientes pasos para completar esta receta:

1. Agregue un nuevo proyecto, asígnele un nombreFormulario Múltiple,y cambie el modelo a Plataforma de


aplicaciones, como se muestra en la siguiente captura de pantalla:

2. Agrega elFormularioEjecutarclass y cree un nuevo método con el siguiente fragmento de código:

addAboutButton privado vacío () {

FormActionPaneControlFormActionPaneControl panel de acción;


FormActionPaneTabControl actionPaneTab;
FormCommandButtonControl cmdAcerca de;
FormButtonGroupControl btngrp;
# define.tareaAcerca(259)

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);
}

3. En la misma clase, anule sucorrer()método con el siguiente fragmento de código:

ejecución de vacío público ()


{
this.addAboutButton();
súper();
}

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.

Almacenamiento de los valores de la última forma


Dynamics 365 for Finance and Operations tiene una función muy útil que le permite guardar las
últimas opciones de usuario por formulario, informe o cualquier otro objeto. Esta función se
implementa en una serie de formularios estándar, informes, trabajos periódicos y otros objetos que
requieren la participación del usuario. Al desarrollar una nueva funcionalidad para Dynamics 365
for Finance and Operations, se recomienda mantenerla así.

[ 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:

1. En el AOT, encuentre elEstado de cuentaform y agregue el siguiente fragmento de


código al final de su declaración de clase:

TodoNoReconciliado showTodoReconciliado;
# define.VersiónActual(1)
# localmacro.CurrentList
showAllReconciled
# endmacro

2. Agregue los siguientes métodos de formulario adicionales:

initParmDefault vacío público () {

showAllReconciled = AllNotReconciled::NotReconciled;
}

paquete contenedor público() {

return [#VersiónActual, #ListaActual];


}

desempaquetado booleano público (contenedor _packedClass) {

versión int = RunBase::getVersion(_packedClass);

interruptor (versión)
{
caso #VersiónActual:
[versión, #CurrentList] = _packedClass; devolver
verdadero;
defecto:
falso retorno;
}

[ 102 ]
Trabajar con formularios

falso retorno;
}

public IdentifierName lastValueDesignName() {

devuelve elemento.args().menuItemName();
}

public IdentifierName lastValueElementName() {

devuelve este.nombre();
}

public UtilElementType lastValueType() {

return UtilElementType::Form;
}

ID de usuario público lastValueUserId () {

volver curUserId();
}

public DataAreaId lastValueDataAreaId() {

volver curaxt();
}

3. Anular el formulariocorrer()y agregue las siguientes líneas de código justo antes


de susúper()método:

xSysLastValue::getLast(esto);
TodoReconciliado.selection(mostrarTodoReconciliado);

4. Anular el formulariocerca()y agregue las siguientes líneas de código en la parte


inferior de este método:

showAllReconciled = AllReconciled.selection();
xSysLastValue::saveLast(esto);

5. Finalmente, elimine la siguiente línea de código delen eso()metodo de la


Estado de cuentafuente de datos:

todoReconciliado.selección(1);

[ 103 ]
Trabajar con formularios

6. Ahora, para probar el formulario, navegue hastaManejo de caja y bancos|Común| cuentas


bancarias, seleccione cualquier cuenta bancaria, haga clic enReconciliación de la cuenta, cambie
el valor del filtro, cierre el formulario y vuelva a abrirlo. La última selección debe permanecer, como
se muestra en la siguiente captura de pantalla:

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

lospaquete()ydeshacer()Los métodos son responsables de formatear un contenedor de almacenamiento a partir de las


variables y extraer variables de un contenedor de almacenamiento, respectivamente. En nuestro caso,
paquete()devuelve un contenedor que consta de dos valores: número de versión y estado de declaración.
Estos valores se enviarán al almacenamiento de datos de uso del sistema después de cerrar el formulario.
Cuando se abre el formulario, elxSysÚltimoValorusos de clasedeshacer()para extraer valores del contenedor
almacenado. Comprueba si la versión del contenedor en los datos de uso coincide con el número de
versión actual definido por #Versión actual,y solo entonces los valores se consideran correctos y se asignan
a las variables del formulario.

Los valores de retorno delastValueDesignName(), lastValueElementName(),


lastValueType(), lastValueUserId(),ylastValueDataAreaId()representar un
combinación única que se utiliza para identificar los datos de uso almacenados. Esto garantiza que diferentes
usuarios puedan almacenar los últimos valores de diferentes objetos en diferentes empresas sin anular los
valores de los demás.

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.

Los dos últimos fragmentos de código deben agregarse al formulariocorrer()ycerca()métodos. En el


correr()método,xSysLastValue::getLast(esto)recupera los valores de usuario guardados de los datos de
uso y los asigna a las variables del formulario.

Finalmente, el código en elcerca()El método es responsable de asignar selecciones de usuario a las


variables y guardarlas en los datos de uso llamando
xSysLastValue::saveLast(esto).

Usando un control de árbol


Los usuarios frecuentes notarán que algunos de los formularios de Dynamics 365 for Finance and Operations usan
controles de árbol en lugar de las cuadrículas de uso común. En algunos casos, esto es extremadamente útil,
especialmente cuando existen relaciones padre-hijo entre los registros. Es una forma mucho más clara de mostrar toda
la jerarquía, en comparación con una lista plana. Por ejemplo, las categorías de productos se organizan como una
jerarquía y brindan una visión general mucho mejor cuando se muestran en un diseño de árbol.

[ 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:

clase pública BudgetModelTree {

Árbol FormTreeControl;
PresupuestoModelId modelId;
}

vacío público nuevo (


FormTreeControl _formTreeControl,
BudgetModelId _budgetModelId)
{
árbol = _formTreeControl;
modeloId = _presupuestoModelId;
}

public static BudgetModelTree construcción (


FormTreeControl _formTreeControl,
BudgetModelId _budgetModelId = '')
{
devuelve el nuevo
BudgetModelTree( _formTreeControl,
_presupuestoModelId);
}

TreeItemIdx privado createNode(


TreeItemIdx _parentIdx,
BudgetModelId _modelId, RecId
_recId)
{
TreeItemIdx itemIdx;
modelo BudgetModel;
submodelo BudgetModel;

[ 106 ]
Trabajar con formularios

modelo = BudgetModel::find(HeadingSub::Heading, _modelId);

itemIdx = SysFormTreeControl::addTreeItem( árbol,

_modelId + ' : ' + modelo.Txt,


_parentIdx,
_recID,
0,
verdadero);
si (IdModelo == _IdModelo) {

árbol.select(elementoIdx);
}
mientras selecciona submodelo
donde submodel.ModelId == _modelId &&
submodel.Type == HeadingSub::SubModel {

this.createNode(
artículoIdx,
submodelo.SubModelId,
submodelo.RecId);
}
devolver itemIdx;
}

public void buildTree() {

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

2. En el AOT, abra elPresupuestoModelodiseño del formulario, expanda elCuerpogrupo,


luego expanda elGridContainergrupo y cambie la siguiente propiedad del
PresupuestoModelocontrol de red:

Propiedad Valor
Visible No

3. Crea un nuevoÁrbolcontrol justo debajo delPresupuestoModelogrilla con estas


propiedades, como se muestra en la siguiente tabla junto con sus valores:

Propiedad Valor
Nombre Árbol

Ancho Ancho de columna

Altura altura de la columna

Borde Linea sola


FilaSeleccionar Sí
Declaración automática Sí

4. Agregue la siguiente línea de código al final de la declaración de clase del formulario:

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();

6. AnularselecciónCambiada()sobre elÁrbolcontrol con el siguiente fragmento de


código:

selección vacía pública cambiada (


FormularioÁrbolElemento _elementoantiguo,

FormularioÁrbolElemento _nuevo artículo,


FormTreeSelect _cómo)
{
PresupuestoModelomodelo;
PresupuestoModelId modelId;

super(_artículo antiguo, _artículo nuevo, _cómo);

[ 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();
}

7. Anular elEliminar()método en elPresupuestoModelofuente de datos con el siguiente


fragmento de código:

eliminación de vacío público ()


{
súper();

si (BudgetModel.RecId)
{
árbolmodelo.construirÁrbol();
}
}

8. Agregue la siguiente línea de código en la parte inferior de laescribe()método en el


PresupuestoModelofuente de datos:

árbolmodelo.construirÁrbol();

9. Anular elEliminar()método en elsubmodelofuente de datos con el siguiente fragmento


de código:

eliminación de vacío público ()


{
súper();

si (SubModelo.RecId)
{
árbolmodelo.construirÁrbol();
}
}

[ 109 ]
Trabajar con formularios

10. Anular elescribe()método en elsubmodelofuente de datos y agregue la siguiente


línea de código en la parte inferior:

árbolmodelo.construirÁrbol();

11. Guarde todo su código y cree su solución.


12. En Visual Studio, elPresupuestoModeloel diseño debe parecerse a la siguiente captura de
pantalla:

13. Para probar elÁrbolcontrolar, navegar apresupuesto|Configuración|Presupuesto básico| Modelos de


presupuesto. Observe cómo los modelos presupuestarios se presentan como una jerarquía, como se muestra
aquí:

[ 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.

La nueva clase contiene algunos métodos comunes, comonuevo()yconstruir(),para


inicializar la clase, y dos métodos que realmente generan el árbol.

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.

En segundo lugar, creamosconstruirÁrbol(),donde se crea todo el árbol. Antes de comenzar a construirlo,


eliminamos todos los nodos existentes (si los hay) en el árbol y luego bloqueamos elÁrbol
control para asegurarse de que el usuario no pueda modificarlo mientras se está construyendo. Luego,
agregamos nodos recorriendo todos los modelos de presupuesto principal y llamando al mencionado
anteriormentecrearNodo().llamamos alexpandirÁrbol()metodo de la
SysFormTreeControlclase para mostrar cada modelo de presupuesto principal que se amplió
inicialmente. Una vez que la jerarquía está lista, desbloqueamos elÁrbolcontrol.

[ 111 ]
Trabajar con formularios

A continuación, modificamos elPresupuestoModeloformulario ocultando la sección de cuadrícula existente y


agregando una nuevaárbolcontrol. Los nodos de árbol siempre se generan a partir del código y la clase mencionada
anteriormente hará exactamente eso. En el formulario, declaramos e inicializamos elmodeloÁrbol
objeto y construir el árbol en el formularioen eso()método.

Para garantizar que el nodo de árbol seleccionado actualmente se muestre en el formulario en


el lado derecho, anulamos elárbolcontrol SselecciónCambiada()evento, que se activa cada vez que
se selecciona un nodo de árbol. Aquí, ubicamos un registro correspondiente y colocamos un
cursor en ese registro.

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

losPrecarga de imágenesreceta enCapítulo 3,Trabajar con datos en formularios los


Creación de una búsqueda de árbolreceta enCapítulo 4,Búsquedas de edificios

Añadir el enlace Ver detalles


Dynamics 365 for Finance and Operations tiene una función muy útil que permite al usuario abrir el formulario
de registro principal con solo unos pocos clics del mouse en el formulario actual. La característica se llamaVer
detallesy está disponible en el menú contextual del botón derecho del ratón en algunos controles. Se basa en
relaciones de tablas y está disponible para aquellos controles cuyos campos de datos tienen relaciones de clave
externa con otras tablas.

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:

1. Agrega ellibro mayordiariotablaforma a su proyecto, ampliar sus fuentes de datos,


y anularsaltoRef()delNombrecampo en ellibro mayordiariotabladatos
source con el siguiente fragmento de código:

public void jumpRef()


{
LedgerJournalName nombre;
argumentos argumentos;

MenúFunción mf;

nombre = LedgerJournalName::find
(LedgerJournalTable.JournalName);

si (!nombre)
{
devolver;
}

argumentos = nuevos argumentos();


args.caller(elemento);
args.record(nombre);

mf = new MenuFunction
(menuitemDisplayStr(LedgerJournalSetup),
MenuItemType::Display);
mf.run(argumentos);
}

2. Guarde todo su código y cree su solución.

[ 113 ]
Trabajar con formularios

3. Navegue hastaLibro mayor|Entradas de diarios|Diario general, seleccione cualquiera de


los registros existentes y haga clic derecho en elDescripcióncolumna. Note que el Ver
detallesopción, que abrirá lanombres de revistasestá disponible ahora, como se muestra
aquí:

Es posible que deba actualizar su página de Dynamics 365 for Operations para reflejar sus
cambios en la interfaz.

4. Al hacer clic enVer detalles, se debe abrir el siguiente formulario:

[ 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

Selección de un patrón de formulario


En la última versión de Dynamics 365 for Finance and Operations, los patrones de formulario ahora son una parte
integrada de la experiencia de desarrollo de formularios. Estos patrones proporcionan una estructura de formulario
basada en un estilo particular (incluidos los controles necesarios y opcionales) y también proporcionan muchas
propiedades de control predeterminadas. Además de los patrones de formulario de nivel superior, Dynamics 365 for
Operations también ha introducido subpatrones que se pueden aplicar a los controles de contenedor y que brindan
orientación y coherencia para el subcontenido en un formulario, por ejemplo, en unPestaña rápida.

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.

La selección de un patrón de formulario es un paso importante en el proceso de migración de un formulario.


Un patrón que se ajuste bien al formulario de destino reduce la cantidad de trabajo de migración necesario.
Por lo tanto, se requiere cierta investigación para seleccionar el mejor patrón de formulario para el formulario
que está migrando.

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:

1. Identifique un formulario de destino y agréguelo a su proyecto. Luego, en Visual Studio, abra


Explorador de aplicacionesy encuentre la forma. Haga clic con el botón derecho en el formulario y
luego seleccione Agregar al proyecto. Cuando abre el formulario en el diseñador, debe tener el
Patrón:<no seleccionado> designación en el nodo de diseño.

[ 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.

Lista completa de patrones de formulario


En la versión actual de Dynamics 365 for Finance and Operations, hay un total de cinco patrones de
formulario que usamos más:

Maestro de detalles

Parte de formulario - Lista simple de

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:

1. Abra VS como administrador y vaya a laDinámica 365menú.


2. Seleccionecomplementos|Ejecutar informe de patrones de formulario:

3. Esto generará un archivo CSV que podremos abrir en Excel.

[ 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:

Aplique su filtro según sus requisitos y vea los resultados.

[ 120 ]
Trabajar con formularios

Creando un nuevo formulario


En Dynamics 365 for Finance and Operations, la creación de formularios es un poco más fácil que en AX2012 y
versiones anteriores. Aquí tenemos más herramientas para crear cualquier formulario específico utilizando plantillas
de diseño. Cada formulario juega un papel importante cuando necesitamos interactuar con el usuario para ver,
insertar, actualizar o eliminar cualquier registro.

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.

2. Ampliar elFuentes de datosnodo y agregue elInformación de usuariotabla en ella:

[ 121 ]
Trabajar con formularios

3. Establezca las siguientes propiedades enFuente de datos:

4. Ir aDiseño, clic derecho enAplicar patróny seleccioneLista sencilla. Esto creará


el patrón respectivo para usted:

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:

9. El diseño de su formulario debería verse así:

[ 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:

11. Ponle un título a tu diseño, comoUsuarios discapacitados con color.Usaremos esta


forma en otras recetas para justificar su nombre:

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 ]

You might also like