Criar um componente de campo de aplicativo controlado por modelo

Neste tutorial, você criará um componente de aplicativo field controlado por modelo e implantará, configurará e testará o componente em um formulário usando Visual Studio Code. Esse componente de código exibe um conjunto de opções no formulário com um ícone ao lado de cada valor de escolha. O componente usa alguns dos recursos avançados de aplicativos controlados por modelos, como definições de coluna de opções (metadados) e segurança em nível de coluna.

Além desses recursos, você garante que o componente de código siga as diretrizes de prática recomendada:

  1. Uso do Microsoft Fluent UI para consistência e acessibilidade.
  2. Localização dos rótulos do componente de código tanto em tempo de design quanto em tempo de execução.
  3. Garantia de que o componente de código é controlado por metadados para melhor reutilização.
  4. Garantia de que o componente de código seja renderizado de acordo com o fator de forma e a largura disponível, exibindo uma lista suspensa compacta com ícones quando o espaço é limitado.

Captura de tela do componente de campo de aplicativo baseado em modelo ChoicesPicker com ícones ao lado de valores de escolha.

Baixar o código de exemplo ChoicesPicker

Você pode baixar o exemplo completo do PowerApps-Samples/component-framework/ChoicesPickerControl/.

Criar um novo projeto do pcfproj

Note

Antes de começar, instale todos os componentes de pré-requisito.

Para criar um novo pcfproj projeto:

  1. Crie uma nova pasta para manter o componente de código. Por exemplo, C:\repos\ChoicesPicker.

  2. Abra o Visual Studio Code e vá para Arquivo>. Selecione a ChoicesPicker pasta que você criou na etapa anterior. Se você adicionou as extensões do Windows Explorer durante a instalação do Visual Studio Code, também poderá usar a opção de menu Abrir com Código dentro da pasta. Você também pode adicionar qualquer pasta a Visual Studio Code usando code . no prompt de comando quando o diretório atual está definido para esse local.

  3. Dentro do novo terminal Visual Studio Code PowerShell (Terminal>Novo Terminal), use o comando pac pcf init para criar um novo projeto de componente de código:

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

    ou use o formulário curto:

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

Esta etapa adiciona arquivos novos ChoicesPicker.pcfproj e relacionados à pasta atual, incluindo um package.json que define os módulos necessários. O comando anterior também executa o npm install comando para instalar os módulos necessários.

Running 'npm install' for you...

Note

Se você receber o erro The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program., certifique-se de instalar node.js (a versão lts é recomendada) e todos os outros pré-requisitos.

Captura de tela do comando pac pcf init criando o componente de código ChoicesPicker.

Você pode ver que o modelo inclui um index.ts arquivo junto com vários arquivos de configuração. Esse arquivo é o ponto inicial do componente de código e contém os métodos de ciclo de vida descritos na implementação do componente.

Instalar a interface do usuário do Microsoft Fluent

Use o Microsoft Fluent UI e o React para criar a interface, então instale estas dependências. Para instalar as dependências, use:

npm install react react-dom @fluentui/react

Esse comando adiciona os módulos ao packages.json arquivo e os instala na node_modules pasta. Não se comprometa com node_modules o controle do código-fonte porque você pode restaurar todos os módulos necessários posteriormente usando npm install.

Uma vantagem do Microsoft Fluent UI é que ele oferece uma interface de usuário consistente e altamente acessível.

configurar eslint

O modelo usado pelo pac pcf init instala o eslint módulo em seu projeto e o configura adicionando um .eslintrc.json arquivo. Você precisa configurar eslint para os estilos de codificação TypeScript e React. Para obter mais informações, consulte Configurar o ESLint para componentes de código.

Editar o manifesto

O ChoicesPicker\ControlManifest.Input.xml arquivo define os metadados que descrevem o comportamento do componente de código. Os atributos de controle já contêm o namespace e o nome do componente.

Defina as seguintes propriedades associadas e de entrada:

Name Usage Tipo Description
Valor bound OptionSet Vincule essa propriedade à coluna de escolha. O componente de código recebe o valor atual e notifica o contexto pai quando o valor é alterado.
Mapeamento de ícones input Várias linhas de texto Essa propriedade terá seu valor definido quando o criador do aplicativo adicionar o componente de código ao formulário. Ele contém uma cadeia de caracteres JSON para configurar quais ícones podem ser usados para cada valor de escolha.

Para obter mais informações, consulte o elemento property.

Tip

Você pode achar o XML mais fácil de ler formatando-o para que os atributos apareçam em linhas separadas. Localize e instale uma ferramenta de formatação XML de sua escolha no Visual Studio Code Marketplace: pesquise extensões de formatação xml.

Os exemplos abaixo foram formatados com atributos em linhas separadas para facilitar a leitura.

Substituir a sampleProperty existente por novas propriedades

Abra o ChoicesPicker\ControlManifest.Input.xml e cole as seguintes definições de propriedade dentro do elemento control, substituindo o sampleProperty existente:

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

Salve as alterações e use o seguinte comando para criar o componente:

npm run build

Depois que o componente for criado, você verá que:

  • Um arquivo ChoicesPicker\generated\ManifestTypes.d.ts gerado automaticamente é adicionado ao seu projeto. O processo de compilação gera este arquivo a partir de ControlManifest.Input.xml e fornece os tipos para interagir com as propriedades de entrada e saída.

  • A saída de build é adicionada à out pasta. O bundle.js é o JavaScript transpilado que é executado no navegador. O ControlManifest.xml é uma versão reformatada do arquivo ControlManifest.Input.xml usada durante a implantação.

    Note

    Não modifique diretamente o conteúdo das pastas out e generated. O processo de compilação os substitui.

Implementar o componente ChoicesPicker Fluent UI React

Quando o componente de código usa React, o updateView método deve renderizar um único componente raiz. Dentro da ChoicesPicker pasta, adicione um novo arquivo TypeScript chamado ChoicesPickerComponent.tsxe adicione o seguinte conteúdo:

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

Note

O arquivo tem a extensão tsx, um arquivo TypeScript que dá suporte à sintaxe de estilo XML usada pelo React. O processo de build o compila em JavaScript padrão.

Notas de design do ChoicesPickerComponent

Esta seção inclui comentários sobre o design do ChoicesPickerComponent.

É um componente funcional

Esse é um componente funcional do React, mas, igualmente, pode ser um componente de classe. Isso se baseia no seu estilo de codificação preferido. Componentes de classe e componentes funcionais também podem ser misturados no mesmo projeto. Os componentes de função e classe usam a tsx sintaxe de estilo XML usada pelo React. Mais informações: Componentes de função e classe

Minimizar o tamanho do bundle.js

Ao importar os componentes Fluent UI ChoiceGroup usando importações baseadas em caminho, em vez de:

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

usamos:

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

Dessa forma, o tamanho do pacote será menor, resultando em requisitos de capacidade mais baixos e melhor desempenho de runtime.

Uma alternativa seria usar o tree-shaking.

Descrição de 'props'

As propriedades de entrada têm os seguintes atributos, que serão fornecidos por index.ts no método updateView.

prop Description
label Usado para rotular o componente. Isso está vinculado ao rótulo do campo de metadados fornecido pelo contexto pai, usando o idioma da interface do usuário selecionado no aplicativo baseado em modelo.
value Vinculado à propriedade de entrada definida no manifesto. Isso pode ser nulo quando o registro é novo ou o campo não está definido. TypeScript null é usado em vez de undefined ao passar/retornar valores de propriedade.
options Quando um componente de código é associado a uma coluna de opções em um aplicativo controlado por modelos, a propriedade contém o OptionMetadata que descreve as opções disponíveis. Você passa isso para o componente para que ele possa renderizar cada item.
configuration A finalidade do componente é mostrar um ícone para cada opção disponível. A configuração é fornecida pelo criador de aplicativos quando eles adicionam o componente de código a um formulário. Essa propriedade aceita uma string JSON que mapeia cada valor numérico de opção para um nome de ícone do Fluent UI. Por exemplo, {"0":"ContactInfo","1":"Send","2":"Phone"}.
onChange Quando o usuário altera a seleção de opções, o componente React dispara o onChange evento. Em seguida, o componente de código chama o notifyOutputChanged para que o aplicativo baseado em modelo possa atualizar a coluna com o novo valor.

Componente React controlado

Há dois tipos de componentes do React:

Tipo Description
Descontrolado Mantenham seu estado interno e usem as props de entrada apenas como valores padrão.
Controlado Renderize o valor passado pelas propriedades do componente. Se o evento onChange não atualizar os valores da prop, o usuário não verá nenhuma mudança na UI.

O ChoicesPickerComponent é um componente controlado, portanto, assim que o aplicativo orientado por modelo atualiza o valor (após a chamada notifyOutputChanged), ele chama updateView com o novo valor, que então é passado para as propriedades do componente, provocando uma nova renderização que exibe o valor atualizado.

Atribuição de desestruturação

A atribuição à constante props: const { label, value, options, onChange, configuration } = props; usa atribuição por desestruturação. Dessa forma, você extrai os atributos necessários para renderizar dos adereços, em vez de prefixá-los com props cada vez que eles são usados.

Uso de componentes e ganchos do React

O seguinte explica como ChoicesPickerComponent.tsx usa os componentes e ganchos do React:

Item Explanation
React.memo Para encapsular nosso componente funcional para que ele não seja renderizado, a menos que qualquer um dos adereços de entrada tenha sido alterado.
React.useMemo Para garantir que o array de itens criado só seja modificado quando as props de entrada configuration ou options tiverem sido alteradas. Essa é uma prática recomendada para componentes funcionais que reduzirão as renderizações desnecessárias dos componentes filho.
React.useCallback Para criar uma closure de callback que é executada quando o valor de Fluent UI ChoiceGroup é alterado. Este hook do React garante que a closure do callback só seja alterada quando a prop de entrada onChange for alterada. Essa é uma prática recomendada de desempenho semelhante a useMemo.

Comportamento em caso de erro para a propriedade de entrada "Configuration"

Se a análise da propriedade de entrada de configuração JSON falhar, o erro será renderizado usando items.error.

Atualizar index.ts para renderizar o componente ChoicesPicker

Você precisa atualizar o arquivo gerado index.ts para renderizar o ChoicesPickerComponent.

Quando você usa o React dentro de um componente de código, o updateView método renderiza o componente raiz. Você passa todos os valores necessários para renderizar o componente no componente. Quando esses valores são alterados, o componente é renderizado novamente.

Adicionar instruções de importação e inicializar ícones

Antes de usar o ChoicesPickerComponent componente no index.ts arquivo, adicione o seguinte código na parte superior do arquivo:

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

Note

Você deve importar initializeIcons porque está usando o conjunto de ícones do Fluent UI. Chame initializeIcons para carregar os ícones dentro do cinto de teste. Dentro de aplicativos controlados por modelos, os ícones já estão inicializados.

Adicionar atributos à classe ChoicesPicker

O componente de código mantém seu estado de instância usando atributos. Esse estado é diferente do estado do componente React. Dentro do index.ts arquivo, adicione os seguintes atributos à ChoicesPicker classe:

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

A tabela a seguir explica estes atributos:

Attribute Description
notifyOutputChanged Mantém uma referência ao método usado para notificar o aplicativo baseado em modelo de que o usuário alterou o valor de uma opção e que o componente de código está pronto para passá-lo de volta ao contexto pai.
rootContainer Elemento HTML DOM criado para conter o componente de código dentro do aplicativo controlado por modelos.
selectedValue Mantém o estado da escolha selecionado pelo usuário para que ele possa ser retornado dentro do getOutputs método.
context o contexto da estrutura de componentes do Power Apps usado para ler as propriedades definidas no manifesto e outras propriedades de tempo de execução, e acessar métodos de API, como trackContainerResize.

Atualizar o método init

Para definir esses atributos, atualize o init método.

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

O init método é chamado quando o componente de código é inicializado em uma tela do aplicativo.

Adicionar o onChange método

Quando o usuário altera o valor selecionado, chame notifyOutputChanged do onChange evento. Adicione uma função:

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

Atualizar o método getOutputs

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

Tip

Se você escreveu scripts de API do cliente antes em aplicativos controlados por modelos, talvez esteja acostumado a usar o contexto de formulário para atualizar valores de atributo. Os componentes de código nunca devem acessar esse contexto. Em vez disso, conte com notifyOutputChanged e getOutputs para fornecer um ou mais valores alterados. Você não precisa retornar todas as propriedades associadas definidas na IOutput interface, apenas as que alteraram o valor.

Atualizar o método updateView

Atualize o método updateView para renderizar o ChoicesPickerComponent:

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

Você obtém o rótulo e as opções de context.parameters.value. Fornece value.raw a opção numérica selecionada ou null se nenhum valor está selecionado.

Editar a função de destruição

Limpe os recursos quando o componente de código for destruído:

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

Para obter mais informações, consulte ReactDOM.unmountComponentAtNode.

Iniciar o arreio de teste

Certifique-se de salvar todos os arquivos. No terminal, use:

npm start watch

Você verá que o ambiente de teste é iniciado com o seletor de opções exibido dentro de uma nova janela do navegador. Inicialmente, ele mostra um erro porque a propriedade configuration de cadeia de caracteres tem o valor valpadrão. Defina a configuração para que ela associe as opções padrão da estrutura de teste 0, 1 e 2 aos seguintes ícones do Fluent UI:

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

Captura de tela do arreio de teste ChoicesPicker mostrando ícones de escolha e o painel Entradas de Dados.

Ao alterar a opção selecionada, você verá o valor no painel Entradas de Dados à direita. Se você alterar o valor, o componente mostrará o valor associado atualizado.

Oferecer suporte à segurança somente leitura e à segurança em nível de coluna

Quando você cria componentes de aplicativos baseados em modelo field, seus aplicativos precisam respeitar o estado do controle quando ele é somente leitura ou está mascarado por causa da segurança em nível de coluna. Se o componente de código não renderizar uma interface somente leitura quando a coluna for somente leitura, em algumas circunstâncias (por exemplo, quando um registro estiver inativo), o usuário poderá atualizar uma coluna quando isso não deveria ser possível. Para obter mais informações, consulte A segurança em nível de coluna para controlar o acesso.

Editar o método updateView para segurança de somente leitura e segurança em nível de coluna

Em index.ts, edite o método updateView para adicionar o código a seguir e obter os sinalizadores masked e disabled:

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

A propriedade value.security está disponível apenas em um aplicativo baseado em modelo quando a configuração de segurança em nível de coluna é aplicada à coluna vinculada.

Passe esses valores para o componente React por meio de suas props.

Editar ChoicesPickerComponent para adicionar as propriedades desabilitadas e mascaradas

Em ChoicesPickerComponent.tsx, aceite as propriedades disabled e masked adicionando-as à interface ChoicesPickerComponentProps:

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

Editar propriedades de ChoicesPickerComponent

Adicione os novos atributos aos adereços.

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

Editar nó de retorno do ChoicesPickerComponent

Dentro do ChoicesPickerComponent, ao retornar os nós do React, use esses novos adereços de entrada para garantir que o seletor esteja desabilitado ou mascarado.

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

Note

Você não deve ver nenhuma diferença no ambiente de teste, porque ele não pode simular campos somente para leitura nem segurança em nível de coluna. Você precisa testar esse recurso depois de implantar o controle em um aplicativo controlado por modelos.

Tornar o componente de código responsivo

Os componentes de código podem ser renderizados na Web, tablet e aplicativos móveis. Considere o espaço disponível. Faça com que o componente de escolhas seja renderizado como uma lista suspensa quando a largura disponível for restrita.

Importar o componente Dropdown e os ícones

Em ChoicesPickerComponent.tsx, o componente renderiza a versão pequena usando o componente Dropdown do Fluent UI, então adicione-o às importações:

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

Adicionar prop formFactor

Atualize o componente de código para renderizar de modo diferente com base em uma nova prop formFactor. Adicione o seguinte atributo à ChoicesPickerComponentProps interface:

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

Adicionar formFactor às propriedades de ChoicesPickerComponent

Adicione formFactor aos adereços.

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

Adicionar métodos e modificar para dar suporte ao componente de lista suspensa

O componente de lista suspensa precisa de diferentes métodos de renderização.

  1. Adicione o seguinte código acima de ChoicesPickerComponent:

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

    Esses métodos permitem que o Dropdown renderize o ícone correto ao lado do valor da lista suspensa.

  2. Adicione um novo onChangeDropDown método.

    Adicione um onChange método para o Dropdown que é semelhante ao ChoiceGroup manipulador de eventos. Adicione a nova Dropdown versão logo após o método existente onChangeChoiceGroup :

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

Alterar a saída renderizada

Faça as seguintes alterações para usar a nova formFactor propriedade.

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

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

Você gera o ChoiceGroup componente quando formFactor é grande e usa Dropdown quando ele é pequeno.

Retornar DropdownOptions

A última coisa que você precisa fazer em ChoicesPickerComponent.tsx é mapear os metadados das opções de forma ligeiramente diferente da forma como o ChoicesGroup faz. No bloco return items, sob o choices: options.map existente, adicione o seguinte código:

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

Agora que o componente de opções é renderizado de forma diferente com base na prop formFactor, passe o valor correto na chamada de renderização dentro de index.ts.

Adicionar SmallFormFactorMaxWidth e o enum FormFactors

Adicione o código a seguir pouco antes da export class ChoicesPicker classe dentro index.ts.

const SmallFormFactorMaxWidth = 350;

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

O SmallFormFactorMaxWidth é a largura quando o componente começa a ser renderizado usando o componente Dropdown em vez do componente ChoiceGroup. A FormFactors enumeração é usada para conveniência ao chamar context.client.getFormFactor.

Adicionar código para detectar formFactor

Adicione o seguinte código às React.createElement props abaixo das props 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 atualizações para redimensionar

Como você está usando context.mode.allocatedWidth, você precisa permitir que o aplicativo controlado por modelos saiba que deseja receber atualizações (por meio de uma chamada para updateView) quando a largura disponível for alterada. Adicione uma chamada para context.mode.trackContainerResize dentro do init método:

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

Experimente no ambiente de teste

Salve todas as alterações para que a janela do navegador do ambiente de teste as reflita automaticamente. Mantenha npm start watch em execução como antes. Alterne o valor da Largura do Contêiner do Componente entre 349 e 350 e veja a renderização se comportar de forma diferente. Troque o fator de forma entre Web e Celular e veja o mesmo comportamento.

Captura de tela da estrutura de teste do ChoicesPicker em resposta às alterações na largura do contêiner e no fator de forma.

Localization

Para dar suporte a vários idiomas, o componente de código pode incluir um arquivo de recurso que fornece traduções para cadeias de caracteres de design e runtime.

  1. Adicione um novo arquivo no local ChoicesPicker\strings\ChoicesPicker.1033.resx. Para adicionar rótulos para uma localidade diferente, altere o 1033 (en-us) para a localidade de sua escolha.

  2. Usando o editor de recursos Visual Studio Code, insira os seguintes valores:

    Name Valor
    ChoicesPicker_Name Seletor de opções (orientado por modelo)
    ChoicesPicker_Desc Mostra as opções como um seletor com ícones
    Value_Name Valor
    Value_Desc O campo de opções ao qual associar o controle
    Configuration_Name Configuração de mapeamento de ícone
    Configuration_Desc Configuração que mapeia o valor da opção para um ícone do Fluent UI. Por exemplo, {"1":"ContactInfo", "2":"Send"}

    Caso contrário, defina o conteúdo do arquivo .resx com o seguinte 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>
    

    Tip

    Não edite resx arquivos diretamente. O editor de recursos Visual Studio Code ou uma extensão para Visual Studio Code facilita essa tarefa.

Atualizar o manifesto para cadeias de caracteres de recurso

Depois de criar as strings de recurso, atualize o ControlManifest.Input.xml para fazer referência a elas.

<?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>

Você pode ver que:

  1. Os valores display-name-key e description-key agora apontam para a chave correspondente no arquivo resx.
  2. Há uma entrada adicional no resources elemento indicando que o componente de código deve carregar recursos do arquivo referenciado.

Se você precisar de mais cadeias de caracteres para usar no seu componente, adicione-as ao arquivo resx e depois carregue as cadeias de caracteres em tempo de execução usando getString. Para obter mais informações, consulte Implementando o componente de API de localização.

Note

Uma limitação da infraestrutura de teste é que ela não carrega arquivos de recursos. Para testar totalmente o componente, você precisa implantar o componente no Microsoft Dataverse.

Implantar e configurar em um aplicativo controlado por modelos

Depois de testar a funcionalidade básica com o arreio de teste, implante o componente para Microsoft Dataverse para que você possa testar totalmente o componente de código de ponta a ponta dentro de um aplicativo controlado por modelos.

  1. Dentro do ambiente do Dataverse, verifique se há um publicador criado com um prefixo de samples:

    Captura de tela do formulário Dataverse para adicionar um editor de soluções com o prefixo de exemplos.

    Você também pode usar seu próprio publicador, desde que atualize o parâmetro de prefixo do publicador na chamada para pac pcf push adequadamente.

    Para obter mais informações, consulte Criar um editor de soluções.

  2. Depois de salvar o publicador, autorize a CLI do Microsoft Power Platform em seu ambiente para que você possa enviar por push o componente de código compilado. Na linha de comando, use:

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

    Substitua myorg.crm.dynamics.com pela URL do seu ambiente do Dataverse. Entre no sistema com privilégios de administrador do sistema ou de personalizador quando solicitado. Essas funções fornecem os privilégios necessários para implantar quaisquer componentes de código no Dataverse.

  3. Para implantar o componente de código, use:

    pac pcf push --publisher-prefix samples
    

    Note

    Se você receber o erro Missing required tool: MSBuild.exe/dotnet.exe, adicione MSBuild.exe/dotnet.exe a variável de ambiente Path ou use Developer Command Prompt for Visual Studio Code. Você deve instalar Visual Studio 2019 para Windows & Mac ou Ferramentas de Build para Visual Studio 2019. Verifique se você selecionou a .NET build tools carga de trabalho conforme descrito nos pré-requisitos.

  4. Quando o processo é concluído, ele cria uma solução temporária chamada PowerAppTools_samples em seu ambiente. O ChoicesPicker componente de código é adicionado a essa solução. Você pode mover o componente de código para sua solução mais tarde, se necessário. Para obter mais informações, consulte ALM (Gerenciamento do Ciclo de Vida do Aplicativo de Componente de Código).

Captura de tela da solução temporária PowerAppTools_samples que contém o componente ChoicesPicker.

  1. Em seguida, adicione o componente de código ao formulário Contatos acessando Formulário Principal no Editor Clássico, selecionando Método Preferido de Contato>>Guia Controles>Adicionar Controle>Selecionar Seletor de Opções>Adicionar.

    Note

    No futuro, você não precisará do editor clássico para configurar componentes de código em formulários de aplicativos controlados por modelos.

  2. Defina as seguintes propriedades no componente:

    • Defina o Seletor de Opções como o padrão para Web, telefone e tablet.

    • Insira a seguinte cadeia de caracteres para a Configuração de Mapeamento de Ícones selecionando o ícone de edição e selecionando Associar a um valor estático.

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

      Esses ícones do Fluent UI são usados para cada opção.

      Captura de tela das propriedades de controle ChoicesPicker com a configuração de mapeamento de ícone.

    • Selecione a guia Exibir e desmarque o rótulo Exibir no formulário , pois você mostra o rótulo acima do seletor de opções.

  3. Salve e publique o formulário.

  4. Abra um registro de contato dentro do aplicativo controlado por modelos com o formulário correto selecionado. Você vê o componente de código ChoicesPicker em vez do controle de lista suspensa padrão. (Talvez seja necessário fazer uma recarga da página para que o componente apareça).

    Note

    Talvez você perceba que o alinhamento do texto é ligeiramente diferente no ambiente de teste em comparação com aplicativos baseados em modelo. Essa diferença ocorre porque a estrutura de teste tem regras de CSS diferentes das dos aplicativos orientados por modelo. Por esse motivo, sempre teste totalmente o componente de código após a implantação.

Depurar após a implantação no Dataverse

Se você precisar fazer mais alterações em seu componente, não precisará implantar a cada vez. Em vez disso, use a técnica descrita em Debug code components para criar um Fiddler AutoResponder para carregar o arquivo do sistema de arquivos local enquanto npm start watch está em execução.

Note

Talvez você não precise depurar após a implantação no Dataverse se puder testar todas as funcionalidades usando o cinto de teste. No entanto, sempre implante e teste dentro do Dataverse antes de distribuir seu componente de código.

O AutoResponder é semelhante ao seguinte:

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

Captura de tela de uma regra do Fiddler AutoResponder que carrega a saída da compilação local do ChoicesPicker.

Você precisa esvaziar o cache e atualizar a sessão do navegador para que o arquivo AutoResponder seja coletado. Depois de carregado, você pode atualizar o navegador, pois o Fiddler adiciona um cabeçalho de controle de cache ao arquivo para impedir que ele seja armazenado em cache.

Quando concluir suas alterações, você poderá incrementar a versão de patch no manifesto e, em seguida, reimplantar usando pac pcf push.

Até agora, você implantou uma build de desenvolvimento que não está otimizada e tem um desempenho mais lento em tempo de execução. Você pode optar por implantar um build otimizado usando o pac pcf push depois de editar o ChoicesPicker.pcfproj arquivo. Sob o OutputPath, adicione o seguinte:

<PcfBuildMode>production</PcfBuildMode>

Gerenciamento do ciclo de vida do aplicativo (ALM) com a Microsoft Power Platform
Referência da API da estrutura de componentes do Power Apps
Criar seu primeiro componente
Depurar componentes de código