Eine Feldkomponente für eine modellgesteuerte App erstellen

In diesem Lernprogramm erstellen Sie eine modellgesteuerte App-Komponente field und stellen die Komponente mithilfe von Visual Studio Code auf einem Formular bereit, konfigurieren und testen. Diese Codekomponente zeigt eine Reihe von Auswahlmöglichkeiten auf dem Formular mit einem Symbol neben jedem Auswahlwert an. Die Komponente verwendet einige der erweiterten Features modellgesteuerter Apps, z. B. Auswahlspaltendefinitionen (Metadaten) und Sicherheit auf Spaltenebene.

Zusätzlich zu diesen Features stellen Sie sicher, dass die Codekomponente den bewährten Methodenleitfaden folgt:

  1. Verwendung der Microsoft Fluent-Benutzeroberfläche für Konsistenz und Barrierefreiheit.
  2. Lokalisierung der Codekomponentenbeschriftungen sowohl bei der Entwurfs- als auch zur Laufzeit.
  3. Sicherheit, dass die Codekomponente metadatengesteuert ist, um die Wiederverwendbarkeit zu verbessern.
  4. Stellen Sie sicher, dass die Codekomponente entsprechend dem Formfaktor und der verfügbaren Breite gerendert wird und eine kompakte Dropdownliste mit Symbolen angezeigt wird, bei denen der Platz begrenzt ist.

Screenshot der modellgesteuerten App-Feldkomponente

Herunterladen des ChoicesPicker-Beispielcodes

Sie können das vollständige Beispiel aus PowerApps-Samples/component-framework/ChoicesPickerControl/herunterladen.

Erstellen eines neuen pcfproj Projekts

Hinweis

Bevor Sie beginnen, stellen Sie sicher, dass Sie alle erforderlichen Komponenten installieren.

So erstellen Sie ein neues pcfproj Projekt:

  1. Erstellen Sie einen neuen Ordner, um die Codekomponente zu speichern. Beispiel: C:\repos\ChoicesPicker.

  2. Öffnen Sie Visual Studio Code, und wechseln Sie zum Ordner "Datei>öffnen". Wählen Sie den ChoicesPicker Ordner aus, den Sie im vorherigen Schritt erstellt haben. Wenn Sie die Windows Explorer-Erweiterungen während der Installation von Visual Studio Code hinzugefügt haben, können Sie auch die Kontextmenüoption "Mit Code öffnen" im Ordner verwenden. Sie können auch einen beliebigen Ordner in Visual Studio Code hinzufügen, indem code . Sie in der Eingabeaufforderung verwenden, wenn das aktuelle Verzeichnis auf diesen Speicherort festgelegt ist.

  3. Verwenden Sie im neuen Visual Studio Code PowerShell-Terminal (Terminal>New Terminal) den Befehl "pac pcf init ", um ein neues Codekomponentenprojekt zu erstellen:

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

    oder verwenden Sie das kurze Formular:

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

In diesem Schritt werden dem aktuellen Ordner neue ChoicesPicker.pcfproj und verwandte Dateien hinzugefügt, einschließlich einer package.json , die die erforderlichen Module definiert. Der vorstehende Befehl führt auch den npm install Befehl aus, um die erforderlichen Module zu installieren.

Running 'npm install' for you...

Hinweis

Wenn der Fehler The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program. auftritt, stellen Sie sicher, dass node.js installiert ist (die LTS-Version wird empfohlen) und alle anderen Voraussetzungen erfüllt sind.

Screenshot des Pac pcf init-Befehls zum Erstellen der ChoicesPicker-Codekomponente.

Sie können sehen, dass die Vorlage eine index.ts Datei zusammen mit verschiedenen Konfigurationsdateien enthält. Diese Datei ist der Ausgangspunkt Ihrer Codekomponente und enthält die in der Komponentenimplementierung beschriebenen Lebenszyklusmethoden.

Installieren der Microsoft Fluent-Benutzeroberfläche

Verwenden Sie Microsoft Fluent UI und React, um die Benutzeroberfläche zu erstellen. Installieren Sie daher diese Abhängigkeiten. Verwenden Sie folgendes, um die Abhängigkeiten zu installieren:

npm install react react-dom @fluentui/react

Mit diesem Befehl werden die Module der packages.json Datei hinzugefügt und in den node_modules Ordner installiert. Checken Sie node_modules nicht in die Quellcodeverwaltung ein, da Sie später mit npm install alle erforderlichen Module wiederherstellen können.

Ein Vorteil der Microsoft Fluent UI besteht darin, dass sie eine konsistente und hochgradig barrierefreie Benutzeroberfläche bietet.

eslint konfigurieren

Die von pac pcf init verwendete Vorlage installiert die eslint-Module in Ihrem Projekt und konfiguriert es durch Hinzufügen einer .eslintrc.json-Datei. Sie müssen eslint für TypeScript- und React-Coding-Stile konfigurieren. Weitere Informationen finden Sie unter Konfigurieren von ESLint für Codekomponenten.

Bearbeiten des Manifests

Die ChoicesPicker\ControlManifest.Input.xml Datei definiert die Metadaten, die das Verhalten der Codekomponente beschreiben. Die Steuerelementattribute enthalten bereits den Namespace und den Namen der Komponente.

Definieren Sie die folgenden gebundenen eigenschaften und Eingabeeigenschaften:

Name Usage Typ Description
Wert bound OptionSet Verknüpfen Sie diese Eigenschaft mit der Auswahlspalte. Die Codekomponente empfängt den aktuellen Wert und benachrichtigt dann den übergeordneten Kontext, wenn sich der Wert ändert.
Symbolzuordnung input Mehrere Textzeilen Der Wert dieser Eigenschaft wird festgelegt, wenn der Anwendungsentwickler die Code-Komponente zum Formular hinzufügt. Sie enthält eine JSON-Zeichenfolge, um zu konfigurieren, welche Symbole für jeden Auswahlwert verwendet werden können.

Weitere Informationen finden Sie unter "Property"-Element.

Tipp

Sie können das XML möglicherweise leichter lesen, wenn Sie es so formatieren, dass Attribute in eigenen Zeilen erscheinen. Suchen und installieren Sie ein XML-Formatierungstool Ihrer Wahl im Visual Studio Code Marketplace: Suchen Sie nach XML-Formatierungserweiterungen.

Die folgenden Beispiele wurden mit Attributen in separaten Zeilen formatiert, damit sie leichter lesbar sind.

Vorhandene SampleProperty durch neue Eigenschaften ersetzen

Öffnen Sie das ChoicesPicker\ControlManifest.Input.xml, fügen Sie die folgenden Eigenschaftendefinitionen in das Steuerelement ein und ersetzen Sie das vorhandene sampleProperty:

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

Speichern Sie die Änderungen, und verwenden Sie dann den folgenden Befehl, um die Komponente zu erstellen:

npm run build

Nachdem die Komponente erstellt wurde, sehen Sie Folgendes:

  • Ihrem Projekt wird eine automatisch generierte Datei ChoicesPicker\generated\ManifestTypes.d.ts hinzugefügt. Der Buildprozess generiert diese Datei aus ControlManifest.Input.xml und stellt die Typen für die Interaktion mit den Eingabe-/Ausgabeeigenschaften bereit.

  • Die Buildausgabe wird dem out Ordner hinzugefügt. Dies bundle.js ist das transpilierte JavaScript, das im Browser ausgeführt wird. Die ControlManifest.xml ist eine neu formatierte Version der ControlManifest.Input.xml Datei, die während der Bereitstellung verwendet wird.

    Hinweis

    Ändern Sie den Inhalt der Ordner generated und out nicht direkt. Der Buildprozess überschreibt sie.

Implementieren der React-Komponente "ChoicesPicker Fluent UI"

Wenn die Codekomponente React verwendet, muss die updateView Methode eine einzelne Stammkomponente rendern. Fügen Sie im ChoicesPicker Ordner eine neue TypeScript-Datei namens ChoicesPickerComponent.tsxhinzu, und fügen Sie den folgenden Inhalt hinzu:

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

Hinweis

Die Datei verfügt über die Erweiterung tsx, eine TypeScript-Datei, die xml-Stilsyntax unterstützt, die von React verwendet wird. Der Buildprozess kompiliert ihn in Standard-JavaScript.

ChoicesPickerComponent-Entwurfsnotizen

Dieser Abschnitt enthält Kommentare zum Design der ChoicesPickerComponent.

Es handelt sich um eine funktionale Komponente

Dies ist eine React-Funktionskomponente, aber auch eine Klassenkomponente. Dies basiert auf Ihrem bevorzugten Codierungsstil. Klassenkomponenten und funktionsbezogene Komponenten können auch im selben Projekt gemischt werden. Sowohl Funktions- als auch Klassenkomponenten verwenden die tsx von React verwendete XML-Stilsyntax. Weitere Informationen: Funktions- und Klassenkomponenten

Minimieren Sie die Größe von bundle.js

Beim Importieren der Fluent UI-Komponente ChoiceGroup mit pfadbasierten Importen anstelle von:

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

wir verwenden:

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

Auf diese Weise wird die Größe des Bundles kleiner, was zu geringeren Kapazitätsanforderungen und einer besseren Laufzeitleistung führt.

Eine Alternative wäre Tree Shaking.

Beschreibung der Eigenschaften

Die Eingabeeigenschaften haben die folgenden Attribute, die von index.ts in der updateView-Methode bereitgestellt werden:

prop Description
label Wird zum Bezeichnen der Komponente verwendet. Ist an die vom übergeordneten Kontext bereitgestellte Metadatenfeldbeschriftung gebunden, wobei die in der modellgesteuerten App ausgewählte Benutzeroberflächensprache verwendet wird.
value Verknüpft mit der im Manifest definierten Eingabeeigenschaft. Dies kann null sein, wenn der Datensatz neu ist oder das Feld nicht festgelegt ist. TypeScript null wird anstelle von undefined bei der Übergabe/Rückgabe von Eigenschaftswerten verwendet.
options Wenn eine Codekomponente an eine Auswahlspalte in einer modellgesteuerten App gebunden ist, enthält die Eigenschaft die OptionMetadata, welche die verfügbaren Auswahlmöglichkeiten beschreibt. Sie übergeben dies an die Komponente, damit jedes Element gerendert werden kann.
configuration Der Zweck der Komponente besteht darin, ein Symbol für jede verfügbare Auswahl anzuzeigen. Die Konfiguration wird vom App-Maker bereitgestellt, wenn sie die Codekomponente zu einem Formular hinzufügen. Diese Eigenschaft akzeptiert eine JSON-Zeichenfolge, die jedem numerischen Auswahlwert einen Fluent UI-Symbolnamen zuordnet. Beispiel: {"0":"ContactInfo","1":"Send","2":"Phone"}.
onChange Wenn der Benutzer die Auswahl ändert, löst die React-Komponente das onChange Ereignis aus. Die Codekomponente ruft dann die notifyOutputChanged So auf, dass die modellgesteuerte App die Spalte mit dem neuen Wert aktualisieren kann.

Kontrollierte React-Komponente

Es gibt zwei Arten von React-Komponenten:

Typ Description
Unkontrolliert Behalten Sie ihren internen Zustand bei und verwenden Sie die Eingabeprops nur als Standardwerte.
Gesteuert Rendern den von den Komponenteneigenschaften übergebenen Wert. Wenn das onChange Ereignis die Prop-Werte nicht aktualisiert, wird dem Benutzer keine Änderung in der Benutzeroberfläche angezeigt.

Dies ChoicesPickerComponent ist eine kontrollierte Komponente. Sobald die modellgesteuerte App den Wert (nach dem notifyOutputChanged Aufruf) aktualisiert hat, ruft sie den updateView neuen Wert auf, der dann an die Komponentenprops übergeben wird, was zu einem erneuten Rendern führt, das den aktualisierten Wert anzeigt.

Destrukturierungszuweisung

Die Zuordnung der props Konstante: const { label, value, options, onChange, configuration } = props; verwendet destrukturierende Zuordnung. Auf diese Weise extrahieren Sie die zum Rendern erforderlichen Attribute aus den Props, anstatt diese bei jeder Verwendung mit props zu versehen.

Verwendung von React-Komponenten und Hooks

Im Folgenden wird erläutert, wie ChoicesPickerComponent.tsx React-Komponenten und Hooks verwendet werden:

Artikel Explanation
React.memo Um unsere Funktionskomponente so zu verpacken, dass sie nicht gerendert wird, es sei denn, die Eingabeeigenschaften werden geändert.
React.useMemo Um sicherzustellen, dass das erstellte Elementarray nur verändert wird, wenn sich die Eingabeprops options oder configuration geändert haben. Dies ist eine bewährte Methode für Funktionskomponenten, die unnötiges Rendering der untergeordneten Komponenten reduziert.
React.useCallback Um eine Rückrufschließung zu erstellen, die aufgerufen wird, wenn sich der ChoiceGroup-Wert der Fluent UI ändern. Dieser React-Hook stellt sicher, dass die Callback-Closure nur verändert wird, wenn das Eingabe-Prop onChange geändert wird. Dies ist eine bewährte Praxis in Bezug auf die Leistung, ähnlich wie useMemo.

Fehlerverhalten für Konfigurationseingabeeigenschaft

Wenn die Analyse der JSON-Konfigurationseingabeeigenschaft fehlschlägt, wird der Fehler mithilfe von items.error dargestellt.

Aktualisieren Sie die index.ts, um die ChoicesPicker-Komponente zu rendern.

Sie müssen die generierte index.ts-Datei aktualisieren, um die ChoicesPickerComponent darzustellen.

Wenn Sie React in einer Codekomponente verwenden, rendert die updateView Methode die Stammkomponente. Sie übergeben alle Werte, die zum Rendern der Komponente benötigt werden, an die Komponente. Wenn sich diese Werte ändern, wird die Komponente erneut gerendert.

Hinzufügen von Importanweisungen und Initialisieren von Symbolen

Bevor Sie die ChoicesPickerComponent Komponente in der Datei verwenden können, fügen Sie oben in der index.ts Datei den folgenden Code hinzu:

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

Hinweis

Sie müssen initializeIcons importieren, da Sie den Fluent UI-Iconsatz verwenden. Rufen Sie initializeIcons auf, um die Symbole innerhalb der Testumgebung zu laden. Innerhalb modellgesteuerter Apps werden die Symbole bereits initialisiert.

Hinzufügen von Attributen zur ChoicesPicker-Klasse

Die Codekomponente verwaltet ihren Instanzstatus mithilfe von Attributen. Dieser Zustand unterscheidet sich vom React-Komponentenstatus. Fügen Sie innerhalb der index.ts-Datei der ChoicesPicker-Klasse die folgenden Attribute hinzu:

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

In der folgenden Tabelle werden die folgenden Attribute erläutert:

Merkmal Description
notifyOutputChanged Enthält einen Verweis auf die Methode, mit der die modellgesteuerte App benachrichtigt wird, dass ein Benutzer einen Auswahlwert geändert hat und die Codekomponente bereit ist, sie an den übergeordneten Kontext zurückzugeben.
rootContainer HTML-DOM-Element, das erstellt wird, um die Codekomponente in der modellgesteuerten App zu speichern.
selectedValue Enthält den Zustand der vom Benutzer ausgewählten Auswahl, sodass er innerhalb der getOutputs Methode zurückgegeben werden kann.
context Power Apps-Komponentenframework-Kontext, der verwendet wird, um die im Manifest definierten Eigenschaften und andere Laufzeiteigenschaften zu lesen, und Zugriff auf API-Methoden wie z. B. trackContainerResize zu erhalten.

Aktualisieren der init Methode

Um diese Attribute festzulegen, aktualisieren Sie die init Methode.

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

Die init Methode wird aufgerufen, wenn die Codekomponente auf einem App-Bildschirm initialisiert wird.

Hinzufügen der onChange Methode

Wenn der Benutzer den ausgewählten Wert ändert, rufen Sie notifyOutputChanged aus dem onChange-Ereignis auf. Funktion hinzufügen:

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

Aktualisieren der getOutputs Methode

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

Tipp

Wenn Sie zuvor in modellgesteuerten Apps Client-API-Skripts geschrieben haben, sind Sie möglicherweise daran gewöhnt, den Formularkontext zum Aktualisieren von Attributwerten zu verwenden. Codekomponenten sollten niemals auf diesen Kontext zugreifen. Stattdessen verlassen Sie sich auf notifyOutputChanged und getOutputs, um einen oder mehrere geänderte Werte bereitzustellen. Sie müssen nicht alle gebundenen Eigenschaften zurückgeben, die in der IOutput Schnittstelle definiert sind, nur diejenigen, die ihren Wert geändert haben.

Aktualisieren der updateView Methode

Aktualisieren Sie die updateView-Methode, um ChoicesPickerComponent zu rendern:

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

Sie rufen die Bezeichnung und die Optionen von context.parameters.value ab. Dies value.raw stellt die ausgewählte numerische Auswahl bereit, oder null wenn kein Wert ausgewählt ist.

Bearbeiten der Vernichtungsfunktion

Bereinigen Sie Ressourcen, wenn die Codekomponente zerstört wird:

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

Weitere Informationen finden Sie unter ReactDOM.unmountComponentAtNode.

Starten des Testgerüsts

Stellen Sie sicher, dass Sie alle Dateien speichern. Verwenden Sie am Terminal:

npm start watch

Sie sehen, dass das Test-Harness mit dem Auswahl-Selektor startet, der in einem neuen Browserfenster gerendert wird. Zunächst wird ein Fehler angezeigt, da die Zeichenfolgeneigenschaft configuration den Standardwert valaufweist. Legen Sie die Konfiguration so fest, dass sie die Standardoptionen der Testumgebung 0, 1 und 2 mit den folgenden Symbolen der Fluent UI abbildet:

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

Screenshot der ChoicesPicker-Testumgebung mit Auswahlsymbolen und dem Bedienfeld „Dateneingaben“.

Wenn Sie die ausgewählte Option ändern, wird der Wert im Bereich "Dateneingaben " auf der rechten Seite angezeigt. Wenn Sie den Wert ändern, zeigt die Komponente den zugeordneten Wert an, der aktualisiert wurde.

Unterstützt schreibgeschützten Zugriff und Sicherheit auf Spaltenebene

Wenn Sie Komponenten für modellgesteuerte Apps field erstellen, müssen Ihre Anwendungen den Steuerelementstatus berücksichtigen, wenn dieser aufgrund von Sicherheit auf Spaltenebene schreibgeschützt oder maskiert ist. Wenn die Codekomponente keine schreibgeschützte Benutzeroberfläche anzeigt, obwohl die Spalte schreibgeschützt ist, kann eine Spalte unter bestimmten Umständen (z. B. wenn ein Datensatz inaktiv ist) vom Benutzer geändert werden, obwohl dies nicht möglich sein sollte. Weitere Informationen finden Sie unter Sicherheit auf Spaltenebene zum Steuern des Zugriffs.

Bearbeiten Sie die updateView-Methode für schreibgeschützte Sicherheit und Sicherheit auf Spaltenebene

Bearbeiten Sie in index.ts die updateView-Methode, um den folgenden Code hinzuzufügen, damit die disabled- und masked-Flags abgerufen werden:

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

Die value.security Eigenschaft ist nur in einer modellgesteuerten App verfügbar, wenn die Sicherheitskonfiguration auf Spaltenebene auf die gebundene Spalte angewendet wird.

Übergeben Sie diese Werte über ihre Props in die React-Komponente.

Ändern Sie die ChoicesPickerComponent, um die Eigenschaften "disabled" und "masked" hinzuzufügen.

Akzeptieren Sie in ChoicesPickerComponent.tsx die Eigenschaften disabled und masked, indem Sie sie zur ChoicesPickerComponentProps-Schnittstelle hinzufügen:

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

Bearbeiten von ChoicesPickerComponent-Eigenschaften

Fügen Sie die neuen Attribute zu den Props hinzu.

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

ChoicesPickerComponent-Rückgabeknoten bearbeiten

Innerhalb des ChoicesPickerComponent verwenden Sie beim Zurückgeben der React-Knoten diese neuen Eingabe-Props, um sicherzustellen, dass der Picker deaktiviert oder maskiert ist.

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

Hinweis

Sie dürften keinen Unterschied in der Testumgebung feststellen, da sie keine schreibgeschützten Felder oder Sicherheit auf Spaltenebene simulieren kann. Sie müssen dieses Feature nach der Bereitstellung des Steuerelements in einer modellgesteuerten Anwendung testen.

Machen Sie die Codekomponente responsiv.

Codekomponenten können in Web-, Tablet- und mobilen Apps gerendert werden. Berücksichtigen Sie den verfügbaren Speicherplatz. Legen Sie fest, dass die Auswahlkomponente als Dropdown gerendert wird, wenn die verfügbare Breite eingeschränkt ist.

Importieren Sie die Dropdown-Komponente und die Symbole

In ChoicesPickerComponent.tsx rendert die Komponente die kleine Variante mithilfe der Fluent UI-Komponente Dropdown, also fügen Sie sie den Importen hinzu:

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

FormFactor-Eigenschaft hinzufügen

Aktualisieren Sie die Codekomponente so, dass sie je nach neuer Eigenschaft formFactoranders gerendert wird. Fügen Sie der ChoicesPickerComponentProps Schnittstelle das folgende Attribut hinzu:

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

Die Eigenschaft formFactor zu den Eigenschaften von ChoicesPickerComponent hinzufügen

Fügen Sie formFactor zu den Props hinzu.

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

Hinzufügen von Methoden und Ändern zur Unterstützung der Dropdownkomponente

Die Dropdownkomponente benötigt unterschiedliche Renderingmethoden.

  1. Fügen Sie den folgenden Code oberhalb von ChoicesPickerComponent hinzu:

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

    Mit diesen Methoden kann das Dropdown das richtige Symbol neben dem Wert im Dropdown-Menü rendern.

  2. Fügen Sie eine neue onChangeDropDown Methode hinzu.

    Fügen Sie eine Methode onChange für Dropdown hinzu, die dem Ereignishandler ChoiceGroup ähnelt. Fügen Sie die neue Dropdown Version direkt nach der vorhandenen onChangeChoiceGroup Methode hinzu:

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

Ändern der gerenderten Ausgabe

Nehmen Sie die folgenden Änderungen vor, um die neue formFactor Eigenschaft zu verwenden.

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

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

Sie geben die Komponente formFactor aus, wenn ChoiceGroup groß ist, und verwenden Dropdown, wenn sie klein ist.

DropdownOptions zurückgeben

Das Letzte, was Sie in ChoicesPickerComponent.tsx tun müssen, ist, die Metadaten der Optionen etwas anders zuzuordnen als von ChoicesGroup verwendet. Fügen Sie im items Rückgabeblock unter dem vorhandenen choices: options.mapCode den folgenden Code hinzu:

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

"Bearbeite index.ts"

Da die Auswahlkomponente jetzt abhängig vom Prop formFactor anders gerendert wird, übergeben Sie den richtigen Wert aus dem Render-Aufruf innerhalb von index.ts.

Fügen Sie SmallFormFactorMaxWidth und die FormFactors-Enumeration hinzu.

Fügen Sie den folgenden Code direkt vor der Klasse index.ts in export class ChoicesPicker ein.

const SmallFormFactorMaxWidth = 350;

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

Die SmallFormFactorMaxWidth ist die Breite bei Beginn des Renderns der Komponente mit der Dropdown- anstatt der ChoiceGroup-Komponente. Die FormFactors-Enumeration wird der Einfachheit halber beim Aufrufen von context.client.getFormFactor verwendet.

Hinzufügen von Code zum Erkennen von formFactor

Fügen Sie den folgenden Code zu den React.createElement Props unterhalb der vorhandenen Props hinzu:

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

Aktualisierungen für Größenanpassung anfordern

Da Sie verwenden context.mode.allocatedWidth, müssen Sie der modellgesteuerten App mitteilen, dass Sie Updates (über einen Aufruf an updateView) empfangen möchten, wenn sich die verfügbare Breite ändert. Fügen Sie in der Methode init einen Aufruf von context.mode.trackContainerResize hinzu:

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

In der Testumgebung ausprobieren

Speichern Sie alle Änderungen, damit das Browserfenster des Test-Harness die Änderungen automatisch übernimmt. Führen Sie npm start watch wie bisher weiter aus. Wechseln Sie den Wert der Komponentencontainerbreite zwischen 349 und 350 , und sehen Sie, dass sich das Rendering anders verhält. Tauschen Sie den Formfaktor zwischen Web und Telefon aus, und sehen Sie dasselbe Verhalten.

Screenshot der ChoicesPicker-Testumgebung bei Änderungen der Containerbreite und des Formfaktors.

Lokalisierung

Um mehrere Sprachen zu unterstützen, kann Ihre Codekomponente eine Ressourcendatei enthalten, die Übersetzungen für Entwurfs- und Laufzeitzeichenfolgen bereitstellt.

  1. Fügen Sie am Speicherort ChoicesPicker\strings\ChoicesPicker.1033.resxeine neue Datei hinzu. Wenn Sie Beschriftungen für ein anderes Gebietsschema hinzufügen möchten, ersetzen Sie 1033 (en-us) durch das Gebietsschema Ihrer Wahl.

  2. Geben Sie mit dem Visual Studio Code Ressourcen-Editor die folgenden Werte ein:

    Name Wert
    ChoicesPicker_Name Auswahlfeld (modellgesteuert)
    ChoicesPicker_Desc Zeigt Auswahlmöglichkeiten als Auswahlliste mit Symbolen an.
    Value_Name Wert
    Value_Desc Das Feld choices, an das das Steuerelement gebunden werden soll
    Configuration_Name Symbolzuordnungskonfiguration
    Configuration_Desc Konfiguration, die den Auswahlwert einem Fluent Ui-Symbol zuordnet. Z. B. {"1":"ContactInfo","2":"Send"}

    Legen Sie andernfalls den Inhalt der RESX-Datei mit dem folgenden XML-Code fest:

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

    Tipp

    Bearbeiten Sie resx Dateien nicht direkt. Der Visual Studio Code Ressourcen-Editor oder eine Erweiterung für Visual Studio Code erleichtert diesen Vorgang.

Das Manifest für Ressourcenzeichenfolgen aktualisieren

Nachdem Sie die Ressourcenzeichenfolgen erstellt haben, aktualisieren Sie die ControlManifest.Input.xml Zeichenfolgen, um auf sie zu verweisen.

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

Sie können folgendes sehen:

  1. Die display-name-key- und description-key-Werte verweisen nun auf den entsprechenden Schlüssel in der resx-Datei.
  2. Es gibt einen zusätzlichen Eintrag im resources Element, der angibt, dass die Codekomponente Ressourcen aus der referenzierten Datei laden soll.

Wenn Sie weitere Zeichenfolgen für die Verwendung in Ihrer Komponente benötigen, fügen Sie sie der resx Datei hinzu, und laden Sie dann die Zeichenfolgen zur Laufzeit mithilfe von getString. Weitere Informationen finden Sie unter Implementieren der Lokalisierungs-API-Komponente.

Hinweis

Eine Einschränkung des Testrahmens besteht darin, dass Ressourcendateien nicht geladen werden. Um die Komponente vollständig zu testen, müssen Sie die Komponente für Microsoft Dataverse bereitstellen.

Bereitstellen und Konfigurieren in einer modellgesteuerten App

Nachdem Sie grundlegende Funktionen mit der Testumgebung getestet haben, stellen Sie die Komponente auf Microsoft Dataverse bereit, damit Sie die Codekomponente vollständig in einer modellgesteuerten App testen können.

  1. Stellen Sie in Ihrer Dataverse-Umgebung sicher, dass ein Herausgeber mit dem Präfix "samples" erstellt wurde.

    Screenshot des Dataverse-Formulars zum Hinzufügen eines Herausgebers einer Lösung mit dem Präfix „samples“.

    Sie können auch Ihren eigenen Herausgeber verwenden, solange Sie den Herausgeberpräfixparameter im Aufruf des Pac pcf-Pushs entsprechend aktualisieren.

    Weitere Informationen finden Sie unter Erstellen eines Lösungsherausgebers.

  2. Nachdem Sie den Publisher gespeichert haben, autorisieren Sie die Microsoft Power Platform CLI für Ihre Umgebung, damit Sie die kompilierte Codekomponente bereitstellen können. Verwenden Sie an der Befehlszeile Folgendes:

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

    Ersetzen Sie myorg.crm.dynamics.com durch die URL Ihrer Dataverse-Umgebung. Melden Sie sich mit einem Systemadministrator oder einer Anpassungsberechtigung an, wenn Sie dazu aufgefordert werden. Diese Rollen stellen die Berechtigungen bereit, die zum Bereitstellen von Codekomponenten auf Dataverse erforderlich sind.

  3. Verwenden Sie Folgendes, um Ihre Codekomponente bereitzustellen:

    pac pcf push --publisher-prefix samples
    

    Hinweis

    Wenn Sie den Fehler Missing required tool: MSBuild.exe/dotnet.exe erhalten, fügen Sie MSBuild.exe/dotnet.exe zur Umgebungsvariable "Path" hinzu oder verwenden Sie Developer Command Prompt for Visual Studio Code. Sie müssen entweder Visual Studio 2019 für Windows & Mac oder Buildtools für Visual Studio 2019 installieren. Stellen Sie sicher, dass Sie die .NET build tools Workload wie in den Voraussetzungen beschrieben auswählen.

  4. Nach Abschluss des Prozesses wird eine temporäre Lösung namens PowerAppTools_samples in Ihrer Umgebung erstellt. Die ChoicesPicker Codekomponente wird dieser Lösung hinzugefügt. Sie können die Codekomponente bei Bedarf später in Ihre Lösung verschieben. Weitere Informationen finden Sie unter Code Component Application Lifecycle Management (ALM).

Screenshot der PowerAppTools_samples temporären Lösung, die die ChoicesPicker-Komponente enthält.

  1. Fügen Sie als Nächstes die Codekomponente zum Formular Kontakte hinzu, indem Sie im Classic Editor zu Hauptformular wechseln und Bevorzugte Kontaktmethode>Eigenschaften ändern>Registerkarte „Steuerelemente“>Steuerelement hinzufügen>Auswahlpicker auswählen>Hinzufügen auswählen.

    Hinweis

    In Zukunft benötigen Sie den klassischen Editor nicht, um Codekomponenten in modellgesteuerten Apps-Formularen zu konfigurieren.

  2. Legen Sie die folgenden Eigenschaften für die Komponente fest:

    • Legen Sie die Auswahlauswahl als Standardeinstellung für Web, Smartphone und Tablet fest.

    • Geben Sie die folgende Zeichenfolge für die Symbolzuordnungskonfiguration ein, indem Sie das Bearbeitungssymbol auswählen und "An einen statischen Wert binden" auswählen.

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

      Diese Fluent UI-Symbole werden für jeden Auswahlwert verwendet.

      Screenshot der Eigenschaften des ChoicesPicker-Steuerelements mit der Symbolzuordnungskonfiguration.

    • Wählen Sie die Registerkarte Anzeige aus und deaktivieren Sie Bezeichnung im Formular anzeigen, da Sie die Bezeichnung oberhalb des Auswahlfelds anzeigen.

  3. Speichern und Veröffentlichen des Formulars.

  4. Öffnen Sie einen Kontaktdatensatz innerhalb der modellgesteuerten App, wobei das richtige Formular ausgewählt ist. Sie sehen die ChoicesPicker Codekomponente anstelle des standardmäßigen Dropdownsteuerelements. (Möglicherweise müssen Sie die Seite erneut laden, damit die Komponente angezeigt wird).

    Hinweis

    Möglicherweise sehen Sie, dass sich die Textausrichtung im Vergleich zu modellgesteuerten Apps in der Testumgebung geringfügig unterscheidet. Dieser Unterschied tritt auf, da die Testumgebung unterschiedliche CSS-Regeln aufweist als modellgesteuerte Apps. Aus diesem Grund testen Sie ihre Codekomponente nach der Bereitstellung immer vollständig.

Debuggen nach der Bereitstellung in Dataverse

Wenn Sie weitere Änderungen an Ihrer Komponente vornehmen müssen, brauchen Sie sie nicht jedes Mal zu deployen. Verwenden Sie stattdessen die in Codekomponenten debuggen beschriebene Technik, um einen Fiddler AutoResponder zu erstellen, um die Datei von Ihrem lokalen Dateisystem zu laden, während npm start watch läuft.

Hinweis

Möglicherweise müssen Sie nach der Bereitstellung in Dataverse nicht debuggen, wenn Sie alle Funktionen mithilfe der Testumgebung testen können. Stellen Sie Ihre Codekomponente jedoch immer in Dataverse bereit und testen Sie sie, bevor Sie sie verteilen.

Der AutoResponder sieht ähnlich wie folgt aus:

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

Screenshot einer Fiddler-AutoResponder-Regel, die die lokale ChoicesPicker-Build-Ausgabe lädt.

Sie müssen in Ihrer Browsersitzung das Cache leeren und Aktualisieren erzwingen, damit die AutoResponder-Datei abgeholt wird. Sobald die Datei geladen ist, können Sie den Browser neu laden, da Fiddler der Datei einen Cache-Control-Header hinzufügt, damit die Datei nicht zwischengespeichert wird.

Wenn Sie mit Ihren Änderungen fertig sind, können Sie die Patchversion im Manifest erhöhen und dann mithilfe des PAC PCF-Pushs erneut bereitstellen.

Bisher haben Sie einen Entwicklungsbuild bereitgestellt, der nicht optimiert ist und zur Laufzeit langsamer ausgeführt wird. Sie können einen optimierten Build bereitstellen, indem Sie nach der Bearbeitung der ChoicesPicker.pcfproj Datei pac pcf push verwenden. Fügen Sie unter OutputPath Folgendes hinzu:

<PcfBuildMode>production</PcfBuildMode>

Application Lifecycle Management (ALM) mit Microsoft Power Platform
Power Apps component framework – API-Referenz
Erstellen Sie Ihre erste Komponente
Debuggen von Code-Komponenten