Compartir a través de


Tutorial: Creación de un componente de campo de aplicación controlado por modelos

En este tutorial, creará un componente de aplicación field controlado por modelos e implementará, configurará y probará el componente en un formulario mediante Visual Studio Code. Este componente de código muestra un conjunto de opciones en el formulario con un icono junto a cada valor de opción. El componente usa algunas de las características avanzadas de las aplicaciones controladas por modelos, como opciones de definiciones de columna (metadatos) y seguridad de nivel de columna.

Además de esto, también garantizará que el componente de código siga las instrucciones de procedimientos recomendados:

  1. Uso de la interfaz de usuario de Microsoft Fluent para la coherencia y accesibilidad
  2. Localización de las etiquetas de componentes de código en el diseño y el entorno de ejecución
  3. Garantía de que el componente de código está controlado por metadatos para mejorar la 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 de PowerApps-Samples/component-framework/ChoicesPickerControl/.

Creación de un nuevo pcfproj proyecto

Nota:

Antes de empezar, asegúrese de que ha instalado todos los componentes de requisitos previos.

Para crear un nuevo pcfproj:

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

  2. Abra Visual Studio Code y vaya a Abrir>carpeta de archivos y, a continuación, seleccione la ChoicesPicker carpeta 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 usar la opción de menú contextual Abrir con código dentro de la carpeta. También puede agregar cualquier carpeta a Visual Studio Code mediante code . en el símbolo del sistema cuando el directorio actual esté establecido en esa ubicación.

  3. Dentro del nuevo terminal de PowerShell de Visual Studio Code (Terminal>nuevo 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 archivos nuevos ChoicesPicker.pcfproj y relacionados a la carpeta actual, incluido un package.json que define los módulos necesarios. El comando anterior también ejecutará el comando npm install para instalar 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 mediante pac pcf init.

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

Instalación de la interfaz de usuario de Microsoft Fluent

Usará la interfaz de usuario de Microsoft Fluent y React para crear la interfaz de usuario, por lo que debe instalarlas como dependencias. Para instalar las dependencias, use:

npm install react react-dom @fluentui/react

Esto agrega los módulos a packages.json e los instala en la node_modules carpeta . 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 la interfaz de usuario de Microsoft Fluent es que proporciona una interfaz de usuario coherente y altamente accesible .

Configuración eslint

La plantilla usada por pac pcf init instala el módulo en el eslint proyecto y lo configura agregando un .eslintrc.json archivo. Eslint requiere la configuración de los estilos de codificación TypeScript y React. Más información: Linting: procedimientos recomendados e instrucciones para componentes de código.

Edición del manifiesto

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

Debe definir las siguientes propiedades vinculadas y de entrada.

Nombre Usage Tipo Description
Valor bound OptionSet Esta propiedad se vinculará a la columna de elección. El componente de código recibe el valor actual y, a continuación, notifica al contexto primario 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 la aplicación agregue el componente de código al formulario. Contiene una cadena JSON para configurar qué iconos se pueden usar para cada valor de opció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 Marketplace de Visual Studio Code: 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 existente por las nuevas propiedades

ChoicesPicker\ControlManifest.Input.xml Abra y pegue las siguientes definiciones de propiedad dentro del elemento de control, reemplazando a la existentesampleProperty:

<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, a continuación, use el siguiente comando para compilar el componente:

npm run build

Una vez compilado el componente, verá lo siguiente:

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

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

    Nota:

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

Implementación del componente ChoicesPicker Fluent UI React

Cuando el componente de código usa React, debe haber un único componente raíz que se represente dentro del updateView método . Dentro de la ChoicesPicker carpeta , agregue un nuevo archivo TypeScript denominado ChoicesPickerComponent.tsxy 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 usada por React. Se compila en JavaScript estándar mediante el proceso de compilación.

Notas de diseño de ChoicesPickerComponent

En esta sección se incluyen comentarios sobre el diseño de ChoicesPickerComponent.

Es un componente funcional

Se trata de un componente funcional de React, pero también 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 usan la tsx sintaxis de estilo XML usada por React. Más información: Componentes de función y clase

Minimizar el tamaño de bundle.js

Al importar los componentes de Fluent UI 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 este modo, el tamaño de la agrupación será menor, lo que dará lugar a 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 proporcionados por index.ts en el updateView método :

prop Description
label Se usa 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 NULL cuando el registro es nuevo o el campo no está establecido. TypeScript null se usa en lugar de undefined cuando se pasan o devuelven valores de propiedad.
options Cuando un componente de código está enlazado a una columna de opciones de una aplicación controlada por modelos, la propiedad contiene el OptionMetadata que describe las opciones disponibles. Esto se pasa al componente para que pueda representar cada elemento.
configuration El propósito del componente es mostrar un icono para cada opción disponible. El creador de la aplicación proporciona la configuración cuando agrega el componente de código a un formulario. Esta propiedad acepta una cadena JSON que asigna cada valor de opción numérico a un nombre de icono de la interfaz de usuario de Fluent. Por ejemplo: {"0":"ContactInfo","1":"Send","2":"Phone"}.
onChange Cuando el usuario cambia la selección de opciones, el componente React desencadena el onChange evento. A continuación, el componente de código llama notifyOutputChanged a para que la aplicación controlada por modelos pueda actualizar la columna con el nuevo valor.

Componente React controlado

Hay dos tipos de componentes de React:

Tipo Description
Descontrolado Mantenga su estado interno y use las propiedades de entrada solo como valores predeterminados.
Controlado Representa el valor pasado por las propiedades del componente. Si el evento onChange no actualiza los valores de las propiedades, el usuario no verá un cambio en la interfaz gráfica de usuario.

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

Asignación de desestructuración

Asignación de la constante props: const { label, value, options, onChange, configuration } = props; usa la asignación por 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 se usan los componentes y enlaces de React:

Elemento Explanation
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 asegurarse de que la matriz de elementos creada solo se muta cuando las propiedades options de entrada o configuration han cambiado. Este es un procedimiento recomendado para los componentes funcionales que reducirán 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 Fluent UI 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. Este es un procedimiento recomendado de rendimiento similar a useMemo.

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

Si se produce un error en el análisis de la propiedad de entrada de configuración JSON, el error se representa mediante 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 updateView método . Todos los valores necesarios para representar el componente se pasan al componente de forma que cuando se cambian y, a continuación, se vuelve a representar.

Agregar instrucciones de importación e inicializar iconos

Antes de poder utilizar el ChoicesPickerComponent en el 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 necesaria porque está utilizando el conjunto de iconos de Fluent UI. Debe llamar a initializeIcons para cargar los iconos dentro del arnés de pruebas. Dentro de las aplicaciones impulsadas por modelos, ya están inicializadas.

Agregar atributos a la clase ChoicesPicker

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

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

En la tabla siguiente se explican estos atributos:

Atributo Description
notifyOutputChanged Contiene una referencia al método usado para notificar a la aplicación controlada por modelos que un usuario ha cambiado un valor de opción y el componente de código está listo para devolverlo al contexto primario.
rootContainer Elemento DOM HTML que se crea para contener el componente de código dentro de la aplicación controlada por modelos.
selectedValue Contiene el estado de la opción seleccionada por el usuario para que se pueda devolver dentro del getOutputs método .
context Contexto de Power Apps component framework que se utiliza para leer las propiedades definidas en el manifiesto y otras propiedades de runtime y métodos de API de acceso, como trackContainerResize.

Actualización del init método

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

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 una pantalla de la aplicación.

Adición del onChange método

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

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

Actualización del getOutputs método

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

Sugerencia

Si ha escrito scripts de API de cliente anteriormente en aplicaciones controladas por modelos, quizás esté acostumbrado a utilizar el contexto del formulario para actualizar los valores de los atributos. Los componentes de código nunca deben tener acceso a este contexto. En su lugar, confíe en notifyOutputChanged y getOutputs para proporcionar uno o varios valores modificados. No es necesario devolver todas las propiedades enlazadas definidas en la IOutput interfaz, solo las que han cambiado su valor.

Actualización del updateView método

Ahora, actualice el updateView para renderizar el ChoicesPickerComponent.

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

Observe que va a extraer la etiqueta y las opciones de context.parameters.value, y 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 se guarden 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 configuration string tiene el valor valpredeterminado . Establezca la configuración para que asocie las opciones predeterminadas del entorno de pruebas 0, 1 y 2 con los siguientes iconos de Fluent UI:

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

Pruebe las opciones de arnés con iconos.

Al cambiar 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.

Soporte para seguridad de solo lectura y a nivel de columna

Al crear componentes de aplicaciones field impulsadas por modelos, las aplicaciones deben respetar el estado de control cuando están en modo solo lectura o enmascaradas debido a la seguridad a nivel de columna. Si el componente de código no representa una interfaz de usuario 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 estar. Más información: Seguridad a nivel de columna para controlar el acceso.

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

En index.ts, edite el método updateView para agregar el siguiente código y obtener los indicadores 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.

Edite ChoicesPickerComponent para agregar las propiedades deshabilitadas y enmascaradas

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

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

Editar las propiedades del componente ChoicesPicker

Agregue los nuevos atributos a los props.

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

Editar el nodo de retorno de 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. Tendrá que probarlo después de implementar el control dentro de una aplicación controlada por modelos.

Hacer que el componente de código responda

Los componentes de código se pueden representar en aplicaciones web, tabletas y móviles. Es importante tener en cuenta el espacio disponible. Haga que el componente de opciones se represente como una lista desplegable cuando el ancho disponible esté restringido.

Importar el componente Dropdown y los Iconos

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

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

Agregar la propiedad formFactor

Actualice el componente de código para que se represente de forma diferente en función de una nueva propiedad formFactor. Agregue el atributo siguiente a la ChoicesPickerComponentProps interfaz :

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 de 'ChoicesPickerComponent'

Agregue 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 dar soporte al 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 mostrar el icono correcto junto al valor desplegable.

  2. Agregue un nuevo onChangeDropDown método.

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

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

Cambio de la salida representada

Realice los siguientes cambios para usar la nueva formFactor propiedad.

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 utiliza Dropdown cuando es pequeño.

Devolver DropdownOptions

Lo último que tenemos que hacer en ChoicesPickerComponent.tsx es asignar los metadatos de opciones de forma ligeramente diferente a lo que usa el ChoicesGroup, por lo que dentro del bloque de retorno de items debajo del existente choices: 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 export class ChoicesPicker clase 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 representarse con el componente Dropdown en lugar del componente ChoiceGroup. FormFactors enum se usa para mayor comodidad al llamar a context.client.getFormFactor.

Adición de código para detectar formFactor

Agregue lo siguiente a las React.createElement propiedades debajo de las propiedades 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,
}),

Solicitud de actualizaciones para cambiar el tamaño

Dado que usa context.mode.allocatedWidth, debe permitir que la aplicación controlada por modelos sepa que desea recibir actualizaciones (a través de una llamada a updateView) cuando cambie el ancho disponible. Dentro del método init, añada 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 del arnés de prueba (ya que npm start watch aún sigue en ejecución desde antes). Ahora puede cambiar el valor de Ancho de contenedor de componentes entre 349 y 350 y ver que la representación se comporta de forma 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 lenguajes, el componente de código puede contener un archivo de recursos que proporcione traducciones para cadenas de diseño y en 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. Con el editor de recursos de Visual Studio Code, escriba lo siguiente:

    Nombre Importancia
    ChoicesPicker_Name Selector de opciones (controlado por modelos)
    ChoicesPicker_Desc Muestra las opciones como selector con iconos
    Value_Name Importancia
    Value_Desc Campo de opciones al que se va a enlazar el control
    Configuration_Name Configuración de asignación de iconos
    Configuration_Desc Configuración que asigna el valor de elección a un icono de Fluent UI. Por ejemplo, {"1":"ContactInfo","2":"Send"}

    De lo contrario, establezca 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 resx archivos directamente. El editor de recursos de Visual Studio Code o una extensión para Visual Studio Code facilita esta tarea.

Actualizar el manifiesto para las cadenas de recursos

Ahora que tiene las cadenas de recursos, puede hacer referencia a ellas actualizando lo ControlManifest.Input.xml siguiente:

<?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 lo siguiente:

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

Si necesita cadenas adicionales para su uso en el componente, puede agregarlas al resx y luego cargar las cadenas durante la ejecución mediante getString. Más información: Implementación del componente de la API de localización.

Nota:

Una de las limitaciones del arnés de pruebas es que no carga archivos de recursos, por lo que debe implementar el componente en Microsoft Dataverse para probar completamente el componente.

Implementación y configuración en una aplicación controlada por modelos

Una vez que haya probado la funcionalidad básica con el arnés 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 controlada por modelos.

  1. Dentro del entorno de Dataverse, asegúrese de que hay un publicador creado con un prefijo de samples:

    Agregar nuevo publicador.

    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: Creación de un publicador 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 insertar el componente de código compilado. En la línea de comandos, use:

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

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

  3. Para implementar el 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 Path o use Developer Command Prompt for Visual Studio Code. Debe instalar Visual Studio 2019 para Windows y Mac o Herramientas de compilación para Visual Studio 2019. Asegúrese de seleccionar la .NET build tools carga de trabajo según lo indicado en los requisitos previos.

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

    PowerAppsTools_sample solución temporal.

  5. A continuación, agregue el componente de código al formulario Contactos y para ello vaya al Formulario principal en el Editor clásico, seleccione Método preferido de contacto>Cambiar Propiedades>Pestaña Controles>Agregar Control>Selector de opciones>Agregar.

    Nota:

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

  6. Establezca las siguientes propiedades en el componente:

    • Establezca el Selector de opciones como valor predeterminado para web, teléfono y tableta.

    • Escriba la siguiente cadena para la Configuración de Asignación de Iconos, seleccionando el icono de edición y luego Enlazar a un valor estático.

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

      Estos son los iconos de la interfaz de usuario de Fluent que se usarán para cada valor de elección.

      Propiedades del 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 controlada por modelos con el formulario correcto seleccionado. Ahora verá el componente de código ChoicesPicker en lugar del control desplegable estándar. (Es posible que tenga que realizar una recarga difícil de la página para que se muestre el componente).

    Nota:

    Es posible que vea que la alineación del texto es ligeramente diferente en el arnés de prueba en comparación con las aplicaciones controladas por modelos. Esto se debe a que el arnés de pruebas tiene reglas CSS diferentes a las de las aplicaciones controladas por modelos. Por este motivo, se recomienda que siempre pruebe completamente el componente de código después de la implementación.

Depurar después de implementar en Dataverse

Si necesita realizar más cambios en el componente, no es necesario implementarlos 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 implementar y probar siempre en Dataverse antes de distribuir el componente de código.

AutoResponder tendría un aspecto similar al siguiente:

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

Regla de AutoResponder.

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

Una vez que haya 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 usando pac pcf push editando el ChoicesPicker.pcfproj. Debajo de OutputPath, agregue lo siguiente:

<PcfBuildMode>production</PcfBuildMode>

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