Compartir a través de


Tutorial: Crear un componente de campo de aplicación basado en modelo

En este tutorial, creará un componente de aplicación basada en modelo field, lo implementará, configurará y probará el componente en un formulario usando Visual Studio Code. Este componente de código muestra un conjunto de opciones en el formulario con un icono al lado de cada valor de elección. El componente utiliza algunas de las funciones avanzadas de las aplicaciones basadas en modelos, como definiciones de columnas de opciones (metadatos) y seguridad a nivel de columna.

Además de estos, también se asegurará de que el componente de código siga la guía de prácticas recomendadas:

  1. Uso de Interfaz de usuario Microsoft Fluent para coherencia y accesibilidad
  2. Localización de las etiquetas de los componentes de código tanto en el diseño como en el runtime
  3. Asegurarse de que el componente de código esté basado en metadatos para una mejor reutilización
  4. Asegurarse de que el componente de código se representa de acuerdo con el factor de forma y el ancho disponible, mostrando un desplegable compacto con iconos en el que el espacio es limitado

Componente ChoicesPicker.

Código

Puede descargar el ejemplo completo en PowerApps-Samples/component-framework/ChoicesPickerControl/.

Crea un nuevo proyecto pcfproj

Nota

Antes de comenzar, asegúrese de haber instalado todos los componentes de los requisitos previos.

Para crear un nuevo pcfproj:

  1. Cree una nueva carpeta para contener su componente de código. Por ejemplo, C:\repos\ChoicesPicker.

  2. Abra Visual Studio Code y vaya a Archivo > Abrir carpeta y seleccione la carpeta ChoicesPicker creada en el paso anterior. Si ha agregado las extensiones del Explorador de Windows durante la instalación de Visual Studio Code, también puede utilizar la opción del menú contextual Abrir con Code dentro de la carpeta. También puede agregar cualquier carpeta en Visual Studio Code usando code . en el símbolo del sistema cuando el directorio actual se establece en esa ubicación.

  3. Dentro de la terminal de PowerShell Visual Studio Code (Terminal > Nueva terminal), use el comando pac pcf init para crear un nuevo proyecto de componente de código:

    pac pcf init `
       --namespace SampleNamespace `
       --name ChoicesPicker `
       --template field `
       --run-npm-install
    

    o usando la forma corta:

    pac pcf init -ns SampleNamespace -n ChoicesPicker -t field -npm
    

Esto agrega un nuevo ChoicesPicker.pcfproj y archivos relacionados a la carpeta actual, incluyendo un package.json que define los módulos necesarios. El comando anterior también ejecutará el comando npm install para que instale los módulos necesarios.

Running 'npm install' for you...

Nota

Si recibe el error The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program., asegúrese de haber instalado todos los requisitos previos, específicamente node.js (Se recomienda la versión LTS) y el resto de prerrequisitos.

Creación de un componente de código usando pac pcf init.

Puede ver que la plantilla incluye un archivo index.ts junto con varios archivos de configuración. Este es el punto de partida de su componente de código y contiene los métodos de ciclo de vida descritos en Implementación de componentes.

Instalar Interfaz de usuario fluida de Microsoft

Utilizará Microsoft Fluent UI y React para crear interfaces de usuario, por lo que debe instalarlos como dependencias. Para instalar las dependencias, use:

npm install react react-dom @fluentui/react

Esto agrega los módulos a packages.json y los instala en la carpeta node_modules. No comprometerá node_modules en control de fuente ya que todos los módulos requeridos se restaurarán más tarde usando npm install.

Una de las ventajas de Microsoft Fluent UI es que proporciona una IU coherente y muy accesible.

Configurando eslint

La plantilla utilizada por pac pcf init instala el módulo eslint a su proyecto y lo configura agregando un archivo .eslintrc.json. Eslint requiere la configuración para los estilos de codificación TypeScript y React. Más información: Linting: mejores prácticas y orientación para componentes de código.

Editar el manifiesto

El archivo ChoicesPicker\ControlManifest.Input.xml define los metadatos que describen el comportamiento del componente de código. Los atributos de control ya tienen el espacio de nombres y el nombre de su componente.

Debe definir las siguientes propiedades bound e input:

Name Uso Type Descripción
valor bound OptionSet Esta propiedad estará vinculada a la columna de opción. El componente de código recibe el valor actual y luego notifica al contexto principal cuando el valor ha cambiado.
Asignación de iconos input Varias líneas de texto Esta propiedad tendrá su valor establecido cuando el creador de aplicaciones agregue el componente de código al formulario. Contiene una cadena JSON para configurar qué iconos pueden usarse para cada valor de elección.

Más información: elemento de propiedad.

Sugerencia

Puede encontrar el XML más fácil de leer si lo formatea para que los atributos aparezcan en líneas separadas. Busque e instale una herramienta de formato XML de su elección en Visual Studio Code Marketplace: Buscar extensiones de formato xml.

Los ejemplos a continuación se han formateado con atributos en líneas separadas para que sean más fáciles de leer.

Reemplazar el sampleProperty con propiedades nuevas

Abra ChoicesPicker\ControlManifest.Input.xml y pegue lo siguiente dentro del elemento de control (reemplazando el existente sampleProperty):

<property name="sampleProperty"
  display-name-key="Property_Display_Key"
  description-key="Property_Desc_Key"
  of-type="SingleLine.Text"
  usage="bound"
  required="true" />

Guarde los cambios y luego use el siguiente comando para compilar el componente:

npm run build

Una vez creado el componente, verá que:

  • Un archivo generado automáticamente ChoicesPicker\generated\ManifestTypes.d.ts se agrega a su proyecto. Esto se genera como parte del proceso de construcción desde ControlManifest.Input.xml y proporciona los tipos para interactuar con las propiedades de entrada / salida.

  • La salida de la compilación se agrega a la carpeta out. bundle.js es el JavaScript transpilado que se ejecuta dentro del navegador. ControlManifest.xml es una versión reformateada del archivo ControlManifest.Input.xml que se utiliza durante la implementación.

    Nota

    No modifique el contenido de las carpetas generated y out directamente. Se sobrescribirán como parte del proceso de compilación.

Implementar el componente de reacción de la interfaz de usuario Fluent ChoicesPicker

Cuando el componente de código usa React, debe haber un solo componente raíz que se representa dentro del método updateView. Dentro de la carpeta ChoicesPicker, agregue un nuevo archivo TypeScript llamado ChoicesPickerComponent.tsx y agregue el siguiente contenido:

import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';
import * as React from 'react';

export interface ChoicesPickerComponentProps {
    label: string;
    value: number | null;
    options: ComponentFramework.PropertyHelper.OptionMetadata[];
    configuration: string | null;
    onChange: (newValue: number | undefined) => void;
}

export const ChoicesPickerComponent = React.memo((props: ChoicesPickerComponentProps) => {
    const { label, value, options, configuration, onChange } = props;
    const valueKey = value != null ? value.toString() : undefined;
    const items = React.useMemo(() => {
        let iconMapping: Record<number, string> = {};
        let configError: string | undefined;
        if (configuration) {
            try {
                iconMapping = JSON.parse(configuration) as Record<number, string>;
            } catch {
                configError = `Invalid configuration: '${configuration}'`;
            }
        }

        return {
            error: configError,
            choices: options.map((item) => {
                return {
                    key: item.Value.toString(),
                    value: item.Value,
                    text: item.Label,
                    iconProps: { iconName: iconMapping[item.Value] },
                } as IChoiceGroupOption;
            }),
        };
    }, [options, configuration]);

    const onChangeChoiceGroup = React.useCallback(
        (ev?: unknown, option?: IChoiceGroupOption): void => {
            onChange(option ? (option.value as number) : undefined);
        },
        [onChange],
    );

    return (
        <>
            {items.error}
            <ChoiceGroup
                label={label}
                options={items.choices}
                selectedKey={valueKey}
                onChange={onChangeChoiceGroup}
            />
        </>
    );
});
ChoicesPickerComponent.displayName = 'ChoicesPickerComponent';

Nota

El archivo tiene la extensión tsx, un archivo TypeScript que admite la sintaxis de estilo XML utilizada por React. Se compila en JavaScript estándar mediante el proceso de compilación.

Notas de diseño de ChoicesPickerComponent

Esta sección incluye comentarios en el diseño de ChoicesPickerComponent.

Es un componente funcional

Este es un componente funcional de React, pero igualmente podría ser un componente de clase. Esto se basa en su estilo de codificación preferido. Los componentes de clase y los componentes funcionales también se pueden mezclar en el mismo proyecto. Tanto los componentes de función como de clase utilizan la sintaxis de estilo tsx XML utilizada por React. Más información: Componentes funcionales y de clase

Minimizar el tamaño de bundle.js

Al importar los componentes de la UI de Fluent ChoiceGroup utilizando importaciones basadas en rutas, en lugar de:

import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react';

usamos:

import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';

De esta forma, el tamaño del paquete será más pequeño, lo que dará como resultado requisitos de capacidad más bajos y un mejor rendimiento en tiempo de ejecución.

Una alternativa sería utilizar temblor de árboles.

Descripción de las "propiedades"

Las propiedades de entrada tienen los siguientes atributos que serán proporcionados por index.ts en el método updateView:

prop Descripción
label Se utiliza para etiquetar el componente. Esto está vinculado a la etiqueta del campo de metadatos que proporciona el contexto principal, utilizando el lenguaje de la interfaz de usuario seleccionado dentro de la aplicación basada en modelo.
value Vinculado a la propiedad de entrada definida en el manifiesto. Esto puede ser nulo cuando el registro es nuevo o el campo no está configurado. TypeScript null se usa en lugar de undefined al pasar / devolver valores de propiedad.
options Cuando un componente de código está vinculado a una columna de opciones en una aplicación basada en modelo, la propiedad contiene la OptionMetadata que describe las opciones disponibles. Pasa esto al componente para que pueda representar cada elemento.
configuration El propósito del componente es mostrar un icono para cada opción disponible. La configuración la proporciona el creador de la aplicación cuando agrega el componente de código a un formulario. Esta propiedad acepta una cadena JSON que asigna cada valor de elección numérica a un nombre de icono de la interfaz de usuario Fluent. Por ejemplo, {"0":"ContactInfo","1":"Send","2":"Phone"}.
onChange Cuando el usuario cambia la selección de opciones, el componente React activa el evento onChange. El componente de código luego llama a notifyOutputChanged para que la aplicación basada en modelos pueda actualizar la columna con el nuevo valor.

Componente React controlado

Existen dos tipos de componentes React:

Type Descripción
Sin control Mantiene su estado interno y usan los accesorios de entrada solo como valores predeterminados.
Controlado Representa el valor pasado por las propiedades del componente. Si el evento onChange no actualiza los valores del accesorio, el usuario no verá un cambio en la interfaz de usuario.

ChoicesPickerComponent es un componente controlado, por lo que una vez que la aplicación basada en modelo ha actualizado el valor (después de la llamada notifyOutputChanged), llama al updateView con el nuevo valor, que luego se pasa a los accesorios del componente, lo que provoca una nueva representación que muestra el valor actualizado.

Asignación de desestructuración

La asignación de la constante props: const { label, value, options, onChange, configuration } = props; usa la asignación de desestructuración. De esta forma, extrae los atributos requeridos para representar a partir de las propiedades, en lugar de prefijarlos con props cada vez que se utilizan.

Uso de componentes y enlaces de React

A continuación se explica cómo ChoicesPickerComponent.tsx utiliza los componentes y enlaces de React:

Item Explicación
React.memo Para encapsular nuestro componente funcional, para que no se represente a menos que alguna de las propiedades de entrada haya cambiado.
React.useMemo Para garantizar que la matriz de elementos creada solo se mute cuando los accesorios de entrada options o configuration cambian. Es un procedimiento recomendado para componentes funcionales que reducirá las representaciones innecesarias de los componentes secundarios.
React.useCallback Para crear un cierre de devolución de llamada que se llama cuando cambia de valor la interfaz de usuario Fluent ChoiceGroup. Este gancho de React asegura que el cierre de devolución de llamada solo se mute cuando el accesorio de entrada onChange está cambiado. Esta es una práctica recomendada de rendimiento similar a useMemo.

Comportamiento de error para la propiedad de entrada de la configuración

Si el análisis de la propiedad de entrada de la configuración JSON falla, el error se representa usando items.error.

Actualizar index.ts para representar el componente ChoicesPicker

Debe actualizar el index.ts file generado para representar ChoicesPickerComponent.

Cuando se usa React dentro de un componente de código, la representación del componente raíz se realiza dentro del método updateView. Todos los valores necesarios para representar el componente se pasan al componente, como cuando se cambian, y luego se vuelve a representar.

Agregar instrucciones de importación e inicializar iconos

Antes de que pueda utilizar ChoicesPickerComponent en index.ts, debe agregar lo siguiente en la parte superior del archivo:

import { IInputs, IOutputs } from "./generated/ManifestTypes";

Nota

La importación de initializeIcons es obligatoria porque está utilizando el conjunto de iconos de Fluent UI. Debe llamar a initializeIcons para cargar los iconos dentro del arnés de prueba. Dentro de las aplicaciones basadas en modelos, ya están inicializados.

Agregar atributos a la clase ChoicesPicker

El componente de código mantiene su estado de instancia mediante atributos. (Esto es diferente al estado del componente React). Dentro de la clase index.ts ChoicesPicker, agregue los atributos siguientes:

export class ChoicesPicker implements ComponentFramework.StandardControl<IInputs, IOutputs> {

En la siguiente tabla, se describen estos atributos:

Attribute Descripción
notifyOutputChanged Contiene una referencia al método utilizado para notificar a la aplicación basada en modelos que un usuario ha cambiado un valor de elección y el componente de código está listo para devolverlo al contexto principal.
rootContainer Elemento DOM HTML que se crea para contener el componente de código dentro de la aplicación basada en modelo.
selectedValue Mantiene el estado de la elección seleccionada por el usuario para que pueda ser devuelto dentro del método getOutputs.
context El contexto de Power Apps component framework que se utiliza para leer las propiedades definidas en el manifiesto y otras propiedades del entorno de tiempo de ejecución y métodos de API de acceso, como trackContainerResize.

Actualizar el método init

Para configurar estos atributos, actualice el método init.

public init(
    context: ComponentFramework.Context<IInputs>, 
    notifyOutputChanged: () => void, 
    state: ComponentFramework.Dictionary, 
    container: HTMLDivElement): 
    void {
    // Add control initialization code
}

El método init se llama cuando el componente de código se inicializa en la pantalla de una aplicación.

Agregar el método onChange

Cuando el usuario cambia el valor seleccionado, debe llamar a notifyOutputChanged desde el evento onChange. Agregar una función:

onChange = (newValue: number | undefined): void => {
     this.selectedValue = newValue;
     this.notifyOutputChanged();
};

Actualizar el método getOutputs

public getOutputs(): IOutputs {
    return {};
}

Sugerencia

Si ha escrito scripts de API de cliente antes en aplicaciones basadas en modelos, es posible que esté acostumbrado a usar el contexto del formulario para actualizar los valores de los atributos. Los componentes de código nunca deben acceder a este contexto. En cambio, confíe en notifyOutputChanged y getOutputs para proporcionar uno o más valores modificados. No es necesario que devuelva todas las propiedades enlazadas definidas en la interfaz IOutput, sino solo las que han cambiado de valor.

Actualizar el método updateView

Ahora, actualice updateView para representar el ChoicesPickerComponent:

public updateView(context: ComponentFramework.Context<IInputs>): void {
    // Add code to update control view
}

Observe que está extrayendo la etiqueta y las opciones de context.parameters.value, y el value.raw proporciona la opción numérica seleccionada, o null si no se selecciona ningún valor.

Editar la función destroy

Por último, debe ordenar cuando se destruye el componente de código:

public destroy(): void {
    // Add code to cleanup control if necessary
}

Más información: ReactDOM.unmountComponentAtNode

Inicie la herramienta de ejecución de pruebas

Asegúrese de que todos los archivos estén guardados y en el terminal use:

npm start watch

Verá que la herramienta de ejecución de pruebas comienza con el selector de opciones representado dentro de una nueva ventana del navegador. Inicialmente, muestra un error porque la propiedad de la cadena configuration tiene el valor predeterminado val. Establezca la configuración para que asigne las opciones predeterminadas de la herramienta de ejecución de pruebas 0,1 y 2 con los siguientes iconos de interfaz de usuario de Fluent:

{"0":"ContactInfo","1":"Send","2":"Phone"}

herramienta de ejecución de pruebas con iconos.

Cuando cambie la opción seleccionada, verá el valor en el panel Entradas de datos de la derecha. Además, si cambia el valor, el componente muestra el valor asociado actualizado.

Compatibilidad con la seguridad de solo lectura y de nivel de columna

Al crear componentes field para aplicaciones basadas en modelo, las aplicaciones deben respetar el estado de control cuando son de solo lectura o enmascaradas debido a la seguridad a nivel de columna. Si el componente de código no representa una IU de solo lectura cuando la columna es de solo lectura, en algunas circunstancias (por ejemplo, cuando un registro está inactivo) el usuario puede actualizar una columna donde no debería ser. Más información: Seguridad a nivel de columna para controlar el acceso.

Editar el método updateView para seguridad de solo lectura y de nivel de columna

En index.ts, edite el método updateView para agregar el siguiente código para obtener las marcas disabled y masked:

public updateView(context: ComponentFramework.Context<IInputs>): void {
    const { value, configuration } = context.parameters;
    if (value && value.attributes && configuration) {
        ReactDOM.render(
            React.createElement(ChoicesPickerComponent, {
                label: value.attributes.DisplayName,
                options: value.attributes.Options,
                configuration: configuration.raw,
                value: value.raw,
                onChange: this.onChange,
            }),
            this.rootContainer,
        );
    }
}

value.security se completará solo dentro de una aplicación basada en modelo si se aplica la configuración de seguridad a nivel de columna a la columna enlazada.

Estos valores luego se pueden pasar al componente React a través de sus propiedades.

Editar ChoicesPickerComponent para agregar las propiedades deshabilitadas y enmascaradas

En ChoicesPickerComponent.tsx, puede aceptar las propiedades disabled y masked agregándolass a la interfaz ChoicesPickerComponentProps:

export interface ChoicesPickerComponentProps {
    label: string;
    value: number | null;
    options: ComponentFramework.PropertyHelper.OptionMetadata[];
    configuration: string | null;
    onChange: (newValue: number | undefined) => void;
}

Editar las propiedades ChoicesPickerComponent

Agregue los nuevos atributos a las propiedades.

export const ChoicesPickerComponent = React.memo((props: ChoicesPickerComponentProps) => {
    const { label, value, options, configuration, onChange } = props;

Editar el nodo de devolución ChoicesPickerComponent

En ChoicesPickerComponent al devolver los nodos de React, puede usar estos nuevos accesorios de entrada para asegurarse de que el selector esté deshabilitado o enmascarado:

return (
    <>
        {items.error}
        <ChoiceGroup
            label={label}
            options={items.choices}
            selectedKey={valueKey}
            onChange={onChangeChoiceGroup}
        />
    </>
);

Nota

No debería ver diferencias en la herramienta de ejecución de pruebas porque no puede simular campos de solo lectura o seguridad a nivel de columna. Deberá probar esto después de implementar el control dentro de una aplicación basada en modelo.

Hacer que el componente de código sea receptivo

Los componentes de código se pueden renderizar en aplicaciones web, tabletas y móviles. Es importante considerar el espacio disponible. Haga que el componente de opciones se represente como un menú desplegable cuando el ancho disponible esté restringido.

Importar el componente desplegable y los iconos

En ChoicesPickerComponent.tsx, el componente representa la versión pequeña usando el componente Dropdown de la IU Fluent, por lo que lo agrega a las importaciones:

import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';
import * as React from 'react';

Agregar la prop formFactor

Actualice el componente de código para representar de manera diferente dependiendo de una nueva prop formFactor. Agregue el atributo siguietne a la interfaz ChoicesPickerComponentProps:

export interface ChoicesPickerComponentProps {
  label: string;
  value: number | null;
  options: ComponentFramework.PropertyHelper.OptionMetadata[];
  configuration: string | null;
  onChange: (newValue: number | undefined) => void;
  disabled: boolean;
  masked: boolean;
}

Agregar formFactor a las propiedades ChoicesPickerComponent

Agregar formFactor a las propiedades.

export const ChoicesPickerComponent = React.memo((props: ChoicesPickerComponentProps) => {
    const { label, value, options, configuration, onChange, disabled, masked  } = props;

Agregar métodos y modificar para admitir el componente desplegable

El componente desplegable necesita algunos métodos de representación diferentes.

  1. Encima de ChoicesPickerComponent, agregue lo siguiente:

    const iconStyles = { marginRight: '8px' };
    
    const onRenderOption = (option?: IDropdownOption): JSX.Element => {
       if (option) {
           return (
             <div>
                 {option.data && option.data.icon && (
                   <Icon
                       style={iconStyles}
                       iconName={option.data.icon}
                       aria-hidden="true"
                       title={option.data.icon} />
                 )}
                 <span>{option.text}</span>
             </div>
           );
       }
       return <></>;
    };
    
    const onRenderTitle = (options?: IDropdownOption[]): JSX.Element => {
       if (options) {
           return onRenderOption(options[0]);
       }
       return <></>;
    };
    

    Estos métodos serán utilizados por Dropdown para representar el icono correcto junto al valor desplegable.

  2. Agregue un nuevo método de onChangeDropDown.

    También necesitamos un método onChange para Dropdown, similar al controlador de eventos ChoiceGroup. Justo debajo del onChangeChoiceGroup existente, agregue la nueva versión Dropdown:

    const onChangeDropDown = React.useCallback(
           (ev: unknown, option?: IDropdownOption): void => {
               onChange(option ? (option.data.value as number) : undefined);
           },
           [onChange],
       );
    

Cambiar la salida renderizada

Realizar los cambios siguientes para utilizar la propiedad formFactor nueva.

return (
  <>
      {items.error}
      {masked && '****'}

      {!items.error && !masked && (
        <ChoiceGroup
            label={label}
            options={items.choices}
            selectedKey={valueKey}
            disabled={disabled}
            onChange={onChangeChoiceGroup}
        />
      )}
  </>
);

Puede ver que genera el componente ChoiceGroup cuando formFactor es grande y usa Dropdown cuando es pequeño.

Devolver DropdownOptions

El último paso en ChoicesPickerComponent.tsx es asignar los metadatos de las opciones de forma ligeramente diferente a la que utiliza el ChoicesGroup, así que dentro del bloque de devolución items, debajo de las choices existentes: options.map, agregue lo siguiente:

return {
    error: configError,
    choices: options.map((item) => {
      return {
          key: item.Value.toString(),
          value: item.Value,
          text: item.Label,
          iconProps: { iconName: iconMapping[item.Value] },
      } as IChoiceGroupOption;
    }),
};

Editar index.ts

Ahora que el componente de opciones se renderizará de manera diferente según el accesorio formFactor, debe pasar el valor correcto de la llamada de renderización dentro de index.ts.

Agregar las enumeraciones SmallFormFactorMaxWidth y FormFactors

Agregue lo siguiente justo encima de la clase export class ChoicesPicker dentro de index.ts.

const SmallFormFactorMaxWidth = 350;

const enum FormFactors {
  Unknown = 0,
  Desktop = 1,
  Tablet = 2,
  Phone = 3,
}

SmallFormFactorMaxWidth es el ancho cuando el componente comienza a renderizarse usando Dropdown en vez del componente ChoiceGroup. FormFactors enum se utiliza por conveniencia al llamar context.client.getFormFactor.

Agregar código para detectar formFactor

Agregue lo siguiente a los accesorios React.createElement debajo de los accesorios existentes:

React.createElement(ChoicesPickerComponent, {
    label: value.attributes.DisplayName,
    options: value.attributes.Options,
    configuration: configuration.raw,
    value: value.raw,
    onChange: this.onChange,
    disabled: disabled,
    masked: masked,
}),

Solicitar actualizaciones para cambiar el tamaño

Ya que está usando context.mode.allocatedWidth, debe informar a la aplicación basada en modelo que desea recibir actualizaciones (a través de una llamada a updateView) cuando cambia el ancho disponible. Hace esto dentro del método init agregando una llamada a context.mode.trackContainerResize:

public init(
    context: ComponentFramework.Context<IInputs>, 
    notifyOutputChanged: () => void, 
    state: ComponentFramework.Dictionary, 
    container: HTMLDivElement): 
    void {
      this.notifyOutputChanged = notifyOutputChanged;
      this.rootContainer = container;
      this.context = context;
}

Probar la herramienta ejecución de pruebas

Ahora guarde todos los cambios, para que se reflejen automáticamente en la ventana del navegador de la herramienta de ejecución de pruebas (porque todavía tiene npm start watch ejecutándose desde antes). Ahora puede cambiar el valor de Ancho del contenedor de componentes entre 349 y 350 y ver cómo el renderizado se comporta de manera diferente. También puede intercambiar el Factor de forma entre Web y Teléfono y ver el mismo comportamiento.

trackContainerResize.

Localización

Si desea admitir varios idiomas, su componente de código puede contener un archivo de recursos que proporciona traducciones tanto para el diseño como para las cadenas de tiempo de ejecución.

  1. Agregue un nuevo archivo en la ubicación ChoicesPicker\strings\ChoicesPicker.1033.resx. Si desea agregar etiquetas para una configuración regional diferente, cambie el 1033 (en-us) al lugar que elija.

  2. Usando el editor de recursos de Visual Studio Code, escriba lo siguiente:

    Name valor
    ChoicesPicker_Name Selector de opciones (basado en modelos)
    ChoicesPicker_Desc Muestra opciones como un selector con iconos
    Value_Name valor
    Value_Desc El campo de opciones al que vincular el control
    Configuration_Name Configuración de la asignación de iconos
    Configuration_Desc Configuración que asigna el valor de elección a un icono de interfaz de usuario fluida. Por ejemplo, {"1":"ContactInfo","2":"Send"}

    De lo contrario, configure el contenido del archivo .resx con el siguiente XML:

    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
        <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
        <xsd:element name="root" msdata:IsDataSet="true">
          <xsd:complexType>
            <xsd:choice maxOccurs="unbounded">
              <xsd:element name="metadata">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0"/>
                  </xsd:sequence>
                  <xsd:attribute name="name" use="required" type="xsd:string"/>
                  <xsd:attribute name="type" type="xsd:string"/>
                  <xsd:attribute name="mimetype" type="xsd:string"/>
                  <xsd:attribute ref="xml:space"/>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="assembly">
                <xsd:complexType>
                  <xsd:attribute name="alias" type="xsd:string"/>
                  <xsd:attribute name="name" type="xsd:string"/>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="data">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
                    <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
                  <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
                  <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
                  <xsd:attribute ref="xml:space"/>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="resheader">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required"/>
                </xsd:complexType>
              </xsd:element>
            </xsd:choice>
          </xsd:complexType>
        </xsd:element>
      </xsd:schema>
      <resheader name="resmimetype">
        <value>text/microsoft-resx</value>
      </resheader>
      <resheader name="version">
        <value>2.0</value>
      </resheader>
      <resheader name="reader">
        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <resheader name="writer">
        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <data name="ChoicesPicker_Name" xml:space="preserve">
        <value>Choices Picker (Model Driven)</value>
        <comment/>
      </data>
      <data name="ChoicesPicker_Desc" xml:space="preserve">
        <value>Shows choices as a picker with icons</value>
        <comment/>
      </data>
      <data name="Value_Name" xml:space="preserve">
        <value>Value</value>
        <comment/>
      </data>
      <data name="Value_Desc" xml:space="preserve">
        <value>The choices field to bind the control to</value>
        <comment/>
      </data>
      <data name="Configuration_Name" xml:space="preserve">
        <value>Icon Mapping Configuration</value>
        <comment/>
      </data>
      <data name="Configuration_Desc" xml:space="preserve">
        <value>Configuration that maps the choice value to a fluent ui icon. E.g. {"1":"ContactInfo","2":"Send"}</value>
        <comment/>
      </data>
    </root>
    

    Sugerencia

    No se recomienda editar archivos resx directamente. El editor de recursos de Visual Studio Code o una extensión para Visual Studio Code lo facilita.

Actualizar el manifiesto para las cadenas de recursos

Ahora que tiene las cadenas de recursos, puede hacer referencia a ellas actualizando el ControlManifest.Input.xml como sigue:

<?xml version="1.0" encoding="utf-8" ?>
<manifest>
  <control namespace="SampleNamespace"
    constructor="ChoicesPicker"
    version="0.0.1"
    display-name-key="ChoicesPicker"
    description-key="ChoicesPicker description"
    control-type="standard">
    <external-service-usage enabled="false">
    </external-service-usage>
    <property name="value"
      display-name-key="Value"
      description-key="Value of the Choices Control"
      of-type="OptionSet"
      usage="bound"
      required="true"/>
    <property name="configuration"
      display-name-key="Icon Mapping"
      description-key="Configuration that maps the choice value to a fluent ui icon."
      of-type="Multiple"
      usage="input"
      required="true"/>
    <resources>
      <code path="index.ts"
        order="1"/>
    </resources>
  </control>
</manifest>

Puede ver que:

  1. Los valores display-name-key y description-key ahora apuntan a la clave correspondiente en el archivo resx.
  2. Hay una entrada adicional en el elemento resources que indica que el componente de código debe cargar recursos desde el archivo referenciado.

Si necesita cadenas adicionales para usar en su componente, puede agregarlas al resx y luego cargue las cadenas en tiempo de ejecución usando getString. Más información: Implementación del componente de API de localización.

Nota

Una de las limitaciones de la herramienta de ejecución de pruebas es que no carga archivos de recursos, por lo que debe implementar el componente para Microsoft Dataverse para probar completamente su componente.

Implementar y configurar en una aplicación basada en modelos

Una vez que haya probado la funcionalidad básica con la herramienta de ejecución de pruebas, debe implementar el componente en Microsoft Dataverse para que el componente de código pueda probarse completamente de un extremo a otro dentro de una aplicación basada en modelo.

  1. Dentro de su entorno de Dataverse, asegúrese de que haya un editor creado con un prefijo de samples:

    Agregar editor nuevo.

    Del mismo modo, este podría ser su editor, siempre que actualice el parámetro de prefijo del editor en la llamada a pac pcf push a continuación. Más información: Crear un editor de soluciones.

  2. Una vez que haya guardado el editor, estará listo para autorizar la Microsoft Power Platform CLI en su entorno para que pueda enviar el componente de código compilado. En la línea de comandos, use:

    pac auth create --url https://myorg.crm.dynamics.com
    

    Reemplace myorg.crm.dynamics.com con la URL de su entorno de Dataverse. Inicie sesión con un Administrador del sistema o privilegios de personalizador cuando se le solicite. Los privilegios proporcionados por estos roles son necesarios para implementar cualquier componente de código en Dataverse.

  3. Para implementar su componente de código, use:

    pac pcf push --publisher-prefix samples
    

    Nota

    Si recibe el error Missing required tool: MSBuild.exe/dotnet.exe, agregue MSBuild.exe/dotnet.exe en la variable de entorno de ruta o use Developer Command Prompt for Visual Studio Code. Debe instalar Visual Studio 2019 para Windows y Mac o Crear herramientas para Visual Studio 2019. Asegúrese de seleccionar la carga de trabajo .NET build tools como se describe en los requisitos previos.

  4. Una vez completado, este proceso crea una solución temporal llamada PowerAppTools_samples en su entorno. El componente de código ChoicesPicker se agregará a esta solución. Puede mover el componente de código a su solución más adelante si es necesario. Más información: Componente de código de Administración del ciclo de vida de las aplicaciones (ALM).

    Solución temporal PowerAppsTools_samples.

  5. A continuación, agregue el componente de código al formulario Contactos yendo a Formulario principal en el Editor clásico, seleccione Método de contacto preferido > Cambiar propiedades > Pestaña controles > Agregar control > Seleccionar selector de opciones > Agregar.

    Nota

    En el futuro, no se necesitará el editor clásico para configurar componentes de código en formularios de aplicaciones controladas por modelos.

  6. Establezca las siguientes propiedades en el componente:

    • Configure el Selector de opciones como predeterminado para la Web, teléfono y tableta.

    • Introduzca la siguiente cadena para la Configuración de asignación de iconos seleccionando el icono de edición y seleccionando Enlazar a un valor estático.

      {
          "1":"ContactInfo",
          "2":"Send", 
          "3":"Phone",
          "4":"Fax",
          "5":"DeliveryTruck"
      }
      

      Estos son los íconos de la interfaz de usuario Fluent que se utilizarán para cada valor de elección.

      Propiedades de control.

    • Seleccione la Pestaña de visualización y desmarque Mostrar etiqueta en el formulario, ya que mostrará la etiqueta sobre el selector de opciones.

  7. Guarde y Publique el formulario.

  8. Abra un registro de contacto dentro de la aplicación basada en modelos con el formulario correcto seleccionado. Ahora verá el componente de código ChoicesPicker en lugar del control desplegable estándar. (Es posible que deba realizar una recarga completa de la página para que aparezca el componente).

    Nota

    Puede ver que la alineación del texto es ligeramente diferente en la herramienta de ejecución de pruebas en comparación con las aplicaciones basadas en modelos. Esto se debe a que el arnés de prueba tiene reglas CSS diferentes a las de las aplicaciones basadas en modelos. Por esta razón, se recomienda que siempre pruebe completamente su componente de código después de la implementación.

Depurar después de implementar a Dataverse

Si necesita realizar más cambios en su componente, no necesita implementarlo cada vez. En su lugar, utilice la técnica descrita en Componentes del código de depuración para crear un Fiddler AutoResponder para cargar el archivo desde su sistema de archivos local mientras se ejecuta npm start watch.

Nota

Es posible que no necesite depurar después de la implementación en Dataverse si toda la funcionalidad se puede probar usando el arnés de prueba. Sin embargo, se recomienda siempre implementar y probar dentro de Dataverse antes de distribuir su componente de código.

La Respuesta automática se vería similar a lo siguiente:

REGEX:(.*?)((?'folder'css|html)(%252f|\/))?SampleNamespace\.ChoicesPicker[\.\/](?'fname'[^?]*\.*)(.*?)$
C:\repos\ChoicesPicker\out\controls\ChoicesPicker\${folder}\${fname}

Regla de respuesta automática.

Necesitará Caché vacío y actualización completa en la sesión de su navegador para que el archivo Respuesta automática sea recogido. Una vez cargado, puede actualizar el navegador, ya que Fiddler agregará un encabezado de control de caché al archivo para evitar que se almacene en caché.

Una vez que ahya terminado sus cambios, puede incrementar la versión del parche en el manifiesto y luego volver a implementar usando pac pcf push..

Hasta ahora, ha implementado una compilación de desarrollo, que no está optimizada y se ejecutará más lentamente en tiempo de ejecución. Puede optar por implementar una compilación optimizada utilizando pac pcf push editando el ChoicesPicker.pcfproj. Debajo de OutputPath, agregue lo siguiente:

<PcfBuildMode>production</PcfBuildMode>

Administración del ciclo de vida de la aplicación (ALM) con Microsoft Power Platform
Referencia de la API de Power Apps component framework
Crear el primer componente
Depurar componentes de código

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).