Freigeben über


Tutorial: Eine Feldkomponente für modellgesteuerte Apps erstellen

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

Darüber hinaus stellen Sie sicher, dass die Codekomponente den Best-Practice-Leitlinien folgt:

  1. Einsatz von Microsoft Fluent UI für Konsistenz und Barrierefreiheit
  2. Lokalisierung der Codekomponentenbezeichnungen sowohl beim Entwurf als auch zur Runtime
  3. Sicherstellung, dass die Codekomponente im Interesse besserer Wiederverwendbarkeit metadatengesteuert ist
  4. Sicherstellung, dass die Codekomponente gemäß dem Formfaktor und verfügbarer Breite rendert und ein kompaktes Dropdownmenü mit Symbolen anzeigt, wenn der Platz begrenzt ist.

ChoicesPicker-Komponente.

Code

Sie können den vollständigen Code für das Beispiel hier herunterladen: PowerApps-Samples/component-framework/ChoicesPickerControl/.

Ein neues pcfproj-Projekt anlegen

Hinweis

Bevor Sie beginnen, stellen Sie sicher, dass Sie alle Voraussetzungskomponenten installiert haben.

Um ein neues pcfproj zu erstellen:

  1. Erstellen Sie einen neuen Ordner für Ihre Codekomponente. Zum Beispiel: C:\repos\ChoicesPicker.

  2. Öffnen Sie Visual Studio Code und gehen Sie dann zu Datei > Ordner öffnen und wählen Sie den im vorherigen Schritt erstellten ChoicesPicker-Ordner aus. 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 mit code . bei der Eingabeaufforderung hinzufügen, wenn das aktuelle Verzeichnis auf diesen Speicherort festgelegt ist.

  3. In dem neuen Visual Studio Code PowerShell-Terminal (Terminal > Neues Terminal) verwenden Sie den pac pcf init Befehl, um ein neues Codekomponentenprojekt zu erstellen:

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

    Alternativ verwenden Sie die Kurzform:

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

Dies fügt dem aktuellen Ordner ein neues ChoicesPicker.pcfproj und die dazugehörigen Dateien hinzu, einschließlich ein package.json, dass die erforderlichen Module festlegt. Der obige Befehl wird auch den Befehl npm install ausführen, um die erforderlichen Module zu installieren.

Running 'npm install' for you...

Hinweis

Wenn Sie den Fehler The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program. erhalten, stellen Sie sicher, dass Sie Node.js (LTS-Version wird empfohlen) und alle anderen Voraussetzungen installiert haben.

Erstellen einer Codekomponente mit pac pcf init.

Wie Sie sehen, enthält die Vorlage eine index.ts-Datei sowie verschiedene Konfigurationsdateien. Dies ist der Ausgangspunkt Ihrer Codekomponente und enthält die in Komponentenimplementierung beschriebenen Lebenszyklusmethoden.

Microsoft Fluent UI installieren

Sie verwenden die Microsoft Fluent UI und React zum Erstellen der Benutzeroberfläche, daher müssen Sie diese als Abhängigkeiten installieren. Um die Abhängigkeiten zu installieren, verwenden Sie:

npm install react react-dom @fluentui/react

Dadurch werden die Module zu den packages.json hinzugefügt und sie im node_modules-Ordner installiert. node_modules wird nicht in die Quellcodeverwaltung eingeschrieben, da alle erforderlichen Module später mit npm install wiederhergestellt werden können.

Einer der Vorteile der Microsoft Fluent UI ist, dass sie eine konsistente und extrem barrierefreie Benutzeroberfläche ist.

Konfiguration von eslint

Die von pac pcf init verwendete Vorlage installiert die eslint-Module in Ihrem Projekt und konfiguriert es durch Hinzufügen einer .eslintrc.json-Datei. Eslint erfordert die Konfiguration für die Codierungsstile TypeScript und React. Weitere Informationen: Linting – Best Practices und Anleitungen für Codekomponenten.

Das Manifest bearbeiten

Die ChoicesPicker\ControlManifest.Input.xml-Datei legt die Metadaten fest, die das Verhalten der Codekomponente beschreiben. Die Steuerelement-Attribute hat bereits den Namenspace und den Namen Ihrer Komponente.

Sie müssen die folgenden gebundenen und Eingabeeigenschaften festlegen:

Name des Dataflows Verbrauch Type Beschreibung
Wert bound OptionSet Diese Eigenschaft wird mit der Auswahlspalte verknüpft. Die Codekomponente empfängt den aktuellen Wert und benachrichtigt dann den übergeordneten Kontext, wenn sich der Wert geändert hat.
Symbolzuordnung input Mehrere Textzeilen Der Wert dieser Eigenschaft wird festgelegt, wenn die die App erstellende Person die Codekomponente zum Formular hinzufügt. Sie enthält eine JSON-Zeichenfolge, um zu konfigurieren, welche Symbole für die einzelnen Auswahlwert verwendet werden können.

Weitere Informationen: Eigenschaftenelement

Tipp

Sie können das XML leichter lesen, wenn Sie es so formatieren, dass die Attribute in separaten Zeilen erscheinen. Suchen und installieren Sie ein XML-Formatierungstool Ihrer Wahl auf dem Visual Studio Code Marketplace: Nach XML-Formatierungserweiterungen suchen.

Die folgenden Beispiele wurden so formatiert, dass die Attribute in separaten Zeilen stehen, um sie besser lesbar zu machen.

Das vorhandene sampleProperty durch neue Eigenschaften ersetzen

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

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

  • Eine automatisch generierte Datei ChoicesPicker\generated\ManifestTypes.d.ts wird Ihrem Projekt hinzugefügt. Diese wird im Rahmen des Erstellen-Prozesses aus dem ControlManifest.Input.xml und stellt die Typen für die Interaktion mit den Eingabe-/Ausgabeeigenschaften bereit.

  • Die Erstellen-Ausgabe wird dem out-Ordner hinzugefügt. Die 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 die Inhalte der generated- und out-Ordner nicht direkt. Sie werden im Rahmen des Build-Prozesses überschrieben.

Die React-Komponente ChoicesPicker der Fluent-Benutzeroberfläche implementieren

Wenn die Codekomponente React verwendet, muss es eine einzelne Stammkomponente geben, die innerhalb der updateView-Methode gerendert wird. Innerhalb des ChoicesPicker-Ordners fügen Sie eine neue TypeScript-Datei mit dem Namen ChoicesPickerComponent.tsx hinzu und 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 hat die Erweiterung tsx und ist eine TypeScript-Datei, die die von React verwendete Syntax im XML-Stil unterstützt. Sie wird durch den Erstellenprozess in Standard-JavaScript kompiliert.

Hinweise zum Design der ChoicesPickerComponent

Dieser Abschnitt enthält Anmerkungen zum Design der ChoicesPickerComponent.

Es ist eine funktionale Komponente

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

Die Größe von bundle.js minimieren

Beim Importieren der Fluent-Benutzeroberflächenkomponente ChoiceGroup mit pfadbasierten Importen anstelle von:

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

Wir verwenden:

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

Dadurch wird Ihre Paketgröße kleiner, was zu geringeren Kapazitätsanforderungen und einer besseren Runtimeleistung 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 Beschreibung
label Wird verwendet, um die Komponente zu beschriften. Ist an die vom übergeordneten Kontext bereitgestellte Metadatenfeldbeschriftung gebunden, wobei die in der modellgesteuerten App ausgewählte Benutzeroberflächensprache verwendet wird.
value Mit der im Manifest definierten Eingabeeigenschaft verknüpft. Dies kann null sein, wenn der Datensatz neu oder das Feld nicht festgelegt ist. TypeScript null wird beim Übergeben/Zurückgeben von Eigenschaftswerten eher verwendet als undefined.
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 sie die einzelnen Element rendern kann.
configuration Der Zweck der Komponente besteht darin, für jede verfügbare Auswahl ein Symbol anzuzeigen. Die Konfiguration wird von der die App erstellenden Person bereitgestellt, wenn er die Codekomponente zu einem Formular hinzufügt. Diese Eigenschaft akzeptiert eine JSON-Zeichenfolge, die jeden numerischen Auswahlwert einem Fluent UI-Symbolnamen zuordnet. Zum Beispiel: {"0":"ContactInfo","1":"Send","2":"Phone"}.
onChange Wenn der Benutzer die Optionsauswahl ändert, löst die React-Komponente das onChange-Ereignis aus. Die Codekomponente ruft dann notifyOutputChanged auf, damit die modellgesteuerte App die Spalte mit dem neuen Wert aktualisieren kann.

Gesteuerte React-Komponente

Es gibt zwei Typen von React-Komponenten:

Type Beschreibung
Nicht gesteuert Behalten ihren internen Status bei und verwenden die Eingabeeigenschaften nur als Standardwerte.
Gesteuert Rendern den von den Komponenteneigenschaften übergebenen Wert. Wenn das onChange-Ereignis die Eigenschaftenwerte nicht aktualisiert, wird dem Benutzer keine Änderung in der Benutzeroberfläche angezeigt.

Die ChoicesPickerComponent ist eine kontrollierte Komponente. Sobald die modellgesteuerte App den Wert aktualisiert hat (nach dem notifyOutputChanged-Aufruf), wird die updateView mit dem neuen Wert aufgerufen, der dann an die Komponenteneigenschaften übergeben wird, was zu einem erneuten Rendering führt, das den aktualisierten Wert anzeigt.

Destrukturierungszuweisung

Die Zuweisung der props Konstante: const { label, value, options, onChange, configuration } = props; verwendet Destrukturierungszuweisung. So extrahieren Sie die Attribute, die zum Rendern erforderlich sind, aus den Eigenschaften, anstatt ihnen jedes Mal das Präfix props voranzustellen, wenn sie verwendet werden.

React-Komponenten und -Hooks verwenden

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

Artikel Erläuterung
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 mutiert wird, wenn die Eingabeeigenschaften options oder configuration geändert werden. 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-Benutzeroberfläche ändern. Dieser React-Hook sorgt dafür, dass die Rückrufschließung nur mutiert wird, wenn sich die Eingabeeigenschaft onChange geändert hat. Dies ist eine bewährte Methode für die Leistung, ähnlich wie useMemo.

Fehlerverhalten für Konfigurationseingabeeigenschaft

Wenn die Analyse der Eingabeeigenschaft der JSON-Konfiguration fehlschlägt, wird der Fehler mit items.error gerendert.

Index.ts aktualisieren, um die ChoicesPicker-Komponente zu rendern

Sie müssen die generierte index.ts file aktualisieren, um die ChoicesPickerComponent zu rendern.

Wenn Sie React innerhalb einer Codekomponente verwenden, wird das Rendern der Stammkomponente innerhalb der Methode updateView durchgeführt. Alle Werte, die zum Rendern der Komponente erforderlich sind, werden an die Komponente übergeben, sodass sie geändert werden. Anschließend wird sie neu gerendert.

Importanweisungen hinzufügen und Symbole initialisieren

Bevor Sie die ChoicesPickerComponent im index.ts verwenden können, müssen Sie am Anfang der Datei Folgendes hinzufügen:

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

Hinweis

Der Import von initializeIcons ist erforderlich, da Sie das Fluent UI-Symbolset verwenden. Sie müssen initializeIcons aufrufen, um die Symbole im Testkabelbaum zu laden. In modellgesteuerten Apps sind sie bereits initialisiert.

Attribute zur ChoicesPicker-Klasse hinzufügen

Die Codekomponente behält ihren Instanzstatus mithilfe von Attributen bei. (Dies unterscheidet sich vom Zustand der React-Komponente). Fügen Sie in der index.ts-ChoicesPicker-Klasse folgende Attribute hinzu:

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

Die folgende Tabelle erklärt diese Attribute:

Attribute Beschreibung
notifyOutputChanged Enthält einen Verweis auf die Methode, die verwendet wird, um die modellgesteuerte App zu benachrichtigen, dass ein Benutzer einen Auswahlwert geändert hat und die Codekomponente bereit ist, ihn an den übergeordneten Kontext zurückzugeben.
rootContainer HTML-DOM-Element, das erstellt wird, um die Codekomponente in der modellgesteuerten App zu speichern.
selectedValue Hält den Status der vom Benutzer ausgewählten Auswahl, damit er in der getOutputs-Methode zurückgegeben werden kann.
context Kontext des Power Apps Component Framework, der verwendet wird, um die im Manifest definierten Eigenschaften und andere Runtime-Eigenschaften zu lesen und auf API-Methoden zuzugreifen, wie z. B. trackContainerResize.

Die init-Methode aktualisieren

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 zum ersten Mal auf einem App-Bildschirm initialisiert wird.

Die onChange-Methode hinzufügen

Wenn der Benutzer den ausgewählten Wert ändert, müssen Sie notifyOutputChanged aus dem onChange-Ereignis abrufen. Fügen Sie eine Funktion hinzu:

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

Die getOutputs-Methode aktualisieren

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

Tipp

Wenn Sie bereits Client-API-Skripts in modellgesteuerten Apps geschrieben haben, sind Sie möglicherweise daran gewöhnt, den Formularkontext zum Aktualisieren von Attributwerten zu verwenden. Codekomponenten sollten niemals auf diesen Kontext zugreifen. Verlassen Sie sich stattdessen 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, sondern nur diejenigen, die ihren Wert geändert haben.

Die updateView-Methode aktualisieren

Aktualisieren Sie jetzt die updateView um die ChoicesPickerComponent zu rendern:

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

Beachten Sie, dass Sie die Beschriftung und die Optionen von context.parameters.value abrufen und der value.raw liefert die gewählte numerische Auswahl oder null, wenn kein Wert ausgewählt ist.

Die destroy-Funktion bearbeiten

Schließlich müssen Sie eine Bereinigung durchführen, wenn die Codekomponente zerstört wird:

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

Weitere Informationen: ReactDOM.unmountComponentAtNode

Die Testumgebung starten

Stellen Sie sicher, dass alle Dateien gespeichert sind und am Terminal verwendet werden:

npm start watch

Sie sehen, dass die Testumgebung mit der Auswahl startet, die in einem neuen Browserfenster gerendert wird. Anfangs wird ein Fehler angezeigt, da die Zeichenfolgeneigenschaft configuration den Standardwert val hat. 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"}

Auswahlmöglichkeiten der Testumgebung mit Symbolen.

Wenn Sie die ausgewählte Option ändern, sehen Sie den Wert im Bereich Dateneingaben auf der rechten Seite. Wenn Sie den Wert ändern, zeigt die Komponente außerdem den zugehörigen Wert aktualisiert an.

Unterstützung des Schreibschutzes oder der Sicherheit auf Spaltenebene

Beim Erstellen von field-Komponenten für modellgesteuerte Apps müssen Anwendungen den Steuerungsstatus respektieren, wenn sie aufgrund der Sicherheit auf Spaltenebene schreibgeschützt oder maskiert sind. Wenn die Codekomponente keine schreibgeschützte Benutzeroberfläche rendert, wenn die Spalte schreibgeschützt ist, es aber nicht sein sollte, kann eine Spalte unter bestimmten Umständen (z. B. wenn ein Datensatz inaktiv ist) vom Benutzer aktualisiert werden. Weitere Informationen: Sicherheit auf Spaltenebene, um den Zugriff zu steuern.

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

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

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 wird in einer modellgesteuerten App nur dann ausgefüllt, wenn die Sicherheitskonfiguration auf Spaltenebene auf die gebundene Spalte angewendet wird.

Diese Werte können dann über ihre Eigenschaften an die React-Komponente übergeben werden.

ChoicesPickerComponent bearbeiten, um die deaktivierten und maskierten Eigenschaften hinzuzufügen

In ChoicesPickerComponent.tsx können Sie die disabled- und masked-Eigenschaften akzeptieren, 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;
}

ChoicesPickerComponent-Eigenschaften bearbeiten

Fügen Sie die neuen Attribute den Eigenschaften hinzu.

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

ChoicesPickerComponent-Rückgabeknoten bearbeiten

Sie können in der ChoicesPickerComponent, bei Rückgabe der React-Knoten, diese neuen Eingabeeigenschaften verwenden, um sicherzustellen, dass die Auswahl 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 dies testen, nachdem Sie das Steuerelement in einer modellgesteuerten Anwendung bereitgestellt haben.

Die Codekomponente reaktionsfähig machen

Codekomponenten können auf Web-, Tablet- und mobilen Apps gerendert werden. Es ist wichtig, den verfügbaren Platz zu berücksichtigen. Lassen Sie die Auswahlkomponente als Dropdownmenü rendern, wenn die verfügbare Breite eingeschränkt ist.

Die Dropdown-Komponente und -Symbole importieren

Die Komponente in ChoicesPickerComponent.tsx rendert die kleine Version mit der Dropdown-Komponente der Fluent-Benutzeroberfläche, also fügen Sie sie zu 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 einer neuen Eigenschaft formFactor unterschiedlich 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;
}

FormFactor zu ChoicesPickerComponent-Eigenschaften hinzufügen

Fügen Sie formFactor den Eigenschaften hinzu.

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

Fügen Sie Methoden hinzu und ändern Sie sie, um Dropdown-Komponenten zu unterstützen

Die Dropdown-Komponente benötigt einige andere Rendering-Methoden.

  1. Fügen Sie über der ChoicesPickerComponent Folgendes 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 <></>;
    };
    

    Diese Methoden werden vom Dropdown verwendet, um das richtige Symbol neben dem Dropdownwert zu rendern.

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

    Wir brauchen eine onChange-Methode für das Dropdown ähnlich des ChoiceGroup-Ereignishandlers. Fügen Sie direkt unter der vorhandenen onChangeChoiceGroup die neue Dropdown-Version hinzu:

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

Die gerenderte Ausgabe hinzufügen

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 sehen, dass die ChoiceGroup-Komponente ausgegeben wird, wenn formFactor groß ist, und das Dropdown genutzt wird, wenn er klein ist.

DropdownOptions zurückgeben

Als Letztes müssen Sie in ChoicesPickerComponent.tsx die Optionsmetadaten ein wenig anders zuordnen als die, die von den ChoicesGroup verwendet werden. Fügen Sie also im items-Rückgabeblock unter den vorhandenen choices options.map Folgendes 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;
    }),
};

Index.ts bearbeiten

Jetzt, da die Auswahlkomponente basierend auf der formFactor-Eigenschaft anders gerendert wird, müssen Sie den richtigen Wert aus dem Render-Aufruf in index.ts übergeben.

Die Enumeration SmallFormFactorMaxWidth und FormFactors hinzufügen

Fügen Sie über der export class ChoicesPicker-Klasse in index.ts Folgendes hinzu.

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 enum dient der Bequemlichkeit beim Abrufen von context.client.getFormFactor.

Code hinzufügen, um formFactor zu erkennen

Fügen Sie Folgendes den React.createElement-Eigenschaften Unterhalb der vorhandenen Eigenschaften 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,
}),

Updates für die Größenänderung anfordern

Da Sie context.mode.allocatedWidth verwenden, müssen Sie der modellgesteuerten App mitteilen, dass Sie Updates erhalten möchten (über einen Aufruf an updateView), wenn sich die verfügbare Breite ändert. Sie tun dies in der init-Methode durch Hinzufügen eines Aufrufs zu 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;
}

In der Testumgebung ausprobieren

Speichern Sie nun alle Änderungen, damit sie automatisch im Browserfenster der Testumgebung angezeigt werden (da npm start watch noch von früher läuft). Sie können jetzt den Wert der Komponentencontainerbreite zwischen 349 und 350 umschalten. Sie sehen, wie sich das Rendering anders verhält. Sie können auch den Formfaktor von Web auf Telefon umstellen und sehe das gleiche Verhalten.

trackContainerResize.

Lokalisierung

Wenn Sie mehrere Sprachen unterstützen möchten, kann Ihre Codekomponente eine Ressourcendatei enthalten, die Übersetzungen für Entwurfs- und Runtime-Zeichenfolgen bereitstellt.

  1. Fügen Sie am Speicherort ChoicesPicker\strings\ChoicesPicker.1033.resx eine neue Datei hinzu. Wenn Sie Beschriftungen für ein anderes Gebietsschema hinzufügen möchten, ändern Sie die 1033 (en-us) auf das Gebietsschema Ihrer Wahl.

  2. Verwenden Sie den Visual Studio Code-Ressourcen-Editor und geben Sie das Folgende ein:

    Name des Dataflows Wert
    ChoicesPicker_Name Choices Picker (modellbasiert)
    ChoicesPicker_Desc Zeigt die Auswahlmöglichkeiten als Picker mit Symbolen an
    Value_Name Wert
    Value_Desc Das Feld choices, an das das Steuerelement gebunden werden soll
    Configuration_Name Symbol Zuordnung Konfiguration
    Configuration_Desc Konfiguration, die den Auswahlwert einem Fluent UI Symbol zuordnet. z. B. {"1":"ContactInfo","2":"Send"}

    Andernfalls legen Sie den Inhalt der .resx-Datei mit dem folgenden XML 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

    Es wird nicht empfohlen, resx-Dateien direkt zu bearbeiten. Der Ressourceneditor Visual Studio Code oder eine Erweiterung für Visual Studio Code erleichtert dies.

Das Manifest für Ressourcenzeichenfolgen aktualisieren

Nachdem Sie nun über die Ressourcenzeichenfolgen verfügen, können Sie darauf verweisen, indem Sie die ControlManifest.Input.xml wie folgt aktualisieren:

<?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 sehen, dass:

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

Wenn Sie zusätzliche Zeichenfolgen für die Verwendung in Ihrer Komponente benötigen, können Sie diese zur resx hinzufügen und dann die Zeichenfolgen zur Runtime mit getString hinzufügen. Weitere Informationen: Implementieren der Lokalisierungs-API-Komponente.

Hinweis

Eine der Einschränkungen der Testumgebung besteht darin, dass keine Ressourcendateien geladen werden, sodass Sie die Komponente an Microsoft Dataverse bereitstellen müssen, um Ihre Komponente vollständig zu testen.

In einer modellgesteuerten App bereitstellen und konfigurieren

Nachdem Sie die grundlegende Funktionalität mit der Testumgebung getestet haben, müssen Sie die Komponente an Microsoft Dataverse bereitstellen, damit die Codekomponente in einer modellgesteuerten App von Anfang bis Ende vollständig getestet werden kann.

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

    Neuen Herausgeber hinzufügen.

    Dies könnte auch Ihr Herausgeber sein, vorausgesetzt, Sie aktualisieren den Herausgeber-Präfix-Parameter im Aufruf von pac pcf push unten. Weitere Informationen: Erstellen eines Lösungsherausgebers.

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

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

    Ersetzen Sie myorg.crm.dynamics.com mit der URL Ihrer Dataverse-Umgebung. Melden Sie sich mit Systemadministrator oder Anpasserprivilegien an, wenn Sie dazu aufgefordert werden. Die von diesen Rollen bereitgestellten Berechtigungen werden benötigt, um Codekomponenten für Dataverse bereitzustellen.

  3. Verwenden Sie zum Bereitstellen Ihrer Codekomponente:

    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 in Path-Umgebungsvariable hinzu oder verwenden Sie Developer Command Prompt for Visual Studio Code. Sie müssen entweder Visual Studio 2019 für Windows & Mac oder Build-Tools für Visual Studio 2019 installieren. Stellen Sie sicher, dass Sie den Workload .NET build tools verwenden, wie in den Voraussetzungen beschrieben.

  4. Nach Abschluss erstellt dieser Vorgang eine temporäre Lösung namens PowerAppTools_Samples in Ihrer Umgebung bereit. 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: Application Lifecycle Management (ALM) für Codekomponenten.

    Temporäre PowerAppsTools_sample-Lösung.

  5. Fügen Sie als Nächstes die Codekomponente zum Formular Kontakte hinzu, indem Sie zum Hauptformular im Klassischen Editor navigieren, wählen Sie Bevorzugte Kontaktmethode > Eigenschaften ändern > Registerkarte „Steuerelemente“ > Steuerelement hinzufügen > Auswahl auswählen > Hinzufügen aus.

    Hinweis

    Zukünftig wird der klassische Editor nicht benötigt, um Codekomponenten auf modellgesteuerten App-Formularen zu konfigurieren.

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

    • Legen Sie die Auswahl als Standard für Web, Telefon und Tablet fest.

    • Geben Sie die folgende Zeichenfolge für die Konfiguration der Symbolzuordnung indem Sie das Bearbeiten-Symbol und An einen statischen Wert binden auswählen.

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

      Dies sind die Fluent UI-Symbole, die für jeden Auswahlwert verwendet werden.

      Eigenschaften des Steuerelements.

    • Wählen Sie die Registerkarte „Anzeigen“ aus und deaktivieren Sie Beschriftung im Formular anzeigen, da Sie die Beschriftung über der Auswahl anzeigen.

  7. Speichern und veröffentlichen des Formulars.

  8. Öffnen Sie einen Kontaktdatensatz in der modellgesteuerten App mit dem richtigen ausgewählten Formular. Sie sehen jetzt die ChoicesPicker Codekomponente anstelle des standardmäßigen Dropdown-Steuerelements. (Möglicherweise müssen Sie die Seite neu laden, damit die Komponente angezeigt wird).

    Hinweis

    Sie werden möglicherweise feststellen, dass sich die Textausrichtung in der Testumgebung geringfügig von modellgesteuerten Apps unterscheidet. Dies liegt daran, dass die Testumgebung andere CSS-Regeln hat als modellgesteuerte Apps. Deshalb sollten Sie Ihre Codekomponente nach der Bereitstellung immer vollständig testen.

Nach der Bereitstellung an Dataverse debuggen

Wenn Sie weitere Änderungen an Ihrer Komponente vornehmen müssen, müssen Sie sie nicht jedes Mal bereitstellen. 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 kein Debuggung durchführen, wenn alle Funktionen mit dem Testkabelbaum getestet werden können. Es wird jedoch empfohlen, immer in Dataverse bereitzustellen und zu testen, bevor Sie Ihre Codekomponente verteilen.

Der AutoResponder würde ungefähr so aussehen:

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

AutoResponder-Regel.

Sie müssen in Ihrer Browsersitzung das Cache leeren und Aktualisieren erzwingen, damit die AutoResponder-Datei abgeholt wird. Nach dem Laden können Sie den Browser aktualisieren, da der Fiddler der Datei eine Cache-Steuerelementkopfzeile hinzufügt, um zu verhindern, dass sie zwischengespeichert wird.

Sobald Sie mit Ihren Änderungen fertig sind, können Sie die Patchversion im Manifest erhöhen und dann mit pac pcf push erneut bereitstellen.

Bisher haben Sie einen Entwicklungs-Build bereitgestellt, der nicht optimiert ist und zur Runtime langsamer ausgeführt wird. Sie können einen optimierten Build bereitstellen, indem Sie pac pcf push durch Bearbeiten der ChoicesPicker.pcfproj verwenden. Fügen Sie unter dem OutputPath Folgendes hinzu:

<PcfBuildMode>production</PcfBuildMode>

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

Hinweis

Können Sie uns Ihre Präferenzen für die Dokumentationssprache mitteilen? Nehmen Sie an einer kurzen Umfrage teil. (Beachten Sie, dass diese Umfrage auf Englisch ist.)

Die Umfrage dauert etwa sieben Minuten. Es werden keine personenbezogenen Daten erhoben. (Datenschutzbestimmungen).