Tutorial: Erstellen einer DataSet-Komponente für Canvas-App
In diesem Tutorial erstellen Sie eine Codekomponente für die Canvas-App, stellen sie bereit, fügen sie einem Bildschirm hinzu und testen die Komponente mit Visual Studio Code. Die Codekomponente zeigt ein seitenweises, scrollbares DataSet-Raster an, das sortierbare und filterbare Spalten bereitstellt. Es ermöglicht auch das Hervorheben bestimmter Zeilen durch Konfigurieren einer Indikatorspalte. Dies ist eine häufige Anfrage von Apps erstellenden Personen und ist mit nativen Canvas-App-Komponenten eventuell komplex zu implementieren. Codekomponenten können so geschrieben werden, dass sie sowohl auf Canvas als auch auf modellgesteuerten Apps funktionieren. Diese Komponente wurde jedoch speziell für die Verwendung in Canvas-Apps geschrieben.
Darüber hinaus stellen Sie sicher, dass die Codekomponente den Best-Practice-Leitlinien folgt:
- Verwendung der Microsoft Fluent UI
- Lokalisierung der Codekomponentenbezeichnungen sowohl beim Entwurf als auch zur Runtime
- Versicherung, dass die Codekomponente in der Breite und Höhe rendert, die vom Bildschirm der übergeordneten Canvas-App bereitgestellt wird
- Überlegung, der App erstellenden Person zu erlauben, die Benutzeroberfläche so weit wie möglich mithilfe von Eingabeeigenschaften und externen App-Elementen anzupassen
Hinweis
Bevor Sie beginnen, stellen Sie sicher, dass Sie alle Voraussetzungskomponenten installiert haben.
Code
Sie können den vollständigen Code für das Beispiel hier herunterladen: PowerApps-Samples/component-framework/CanvasGridControl/.
Ein neues pcfproj
-Projekt anlegen
Erstellen Sie einen neuen Ordner, den Sie für Ihre Codekomponente verwenden möchten. Zum Beispiel:
C:\repos\CanvasGrid
.Öffnen Sie Visual Studio Code und dann Datei > Ordner öffnen und wählen Sie den Ordner
CanvasGrid
aus. Wenn Sie die Windows-Explorer-Erweiterungen während der Installation von Visual Studio Code hinzugefügt haben, können Sie die Kontextmenüoption Mit Code öffnen im Ordner verwenden. Sie können auch einen beliebigen Ordner in Visual Studio Code mitcode .
bei der Eingabeaufforderung laden, wenn das aktuelle Verzeichnis auf diesen Speicherort festgelegt ist.Verwenden Sie in einem neuen Visual Studio Code PowerShell-Terminal (Terminal > Neues Terminal) den Befehl pac pcf init, um ein neues Codekomponentenprojekt zu erstellen:
pac pcf init --namespace SampleNamespace --name CanvasGrid --template dataset
Alternativ verwenden Sie die Kurzform:
pac pcf init -ns SampleNamespace -n CanvasGrid -t dataset
Dies fügt dem aktuellen Ordner ein neues
pcfproj
und die dazugehörigen Dateien hinzu, einschließlich einpackages.json
, dass die Module festlegt. Um die erforderlichen Module zu installieren, verwenden Sie NPM installieren:npm install
Hinweis
Wenn Sie die Nachricht
The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program.
erhalten, stellen Sie sicher, dass Sie alle Voraussetzungen installiert haben, insbesondere Node.js (LTS-Version wird empfohlen).
Die Vorlage enthält 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. Verwenden Sie am Terminal Folgendes:
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 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 jetzt die Konfiguration für die Codierungsstile TypeScript und React. Weitere Informationen: Linting – Best Practices und Anleitungen für Codekomponenten.
Die DataSet-Eigenschaften festlegen
Die CanvasGrid\ControlManifest.Input.xml
-Datei legt die Metadaten fest, die das Verhalten der Codekomponente beschreiben. Das Steuerelement-Attribut hat bereits den Namenspace und den Namen der Komponente.
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.
Sie müssen die Datensätze definieren, an die die Codekomponente gebunden werden kann, indem Sie Folgendes im control
-Element hinzufügen, das das vorhandene data-set
-Element ersetzt:
Das Datensatz-DataSet wird an Datenquelle gebunden, wenn die Codekomponente zu einer Canvas-App hinzugefügt wird. Der Eigenschaftensatz gibt an, dass der Benutzer eine der Spalten dieses DataSet konfigurieren muss, um als Zeilenhervorhebungsindikator verwendet zu werden.
Tipp
Sie können mehrere DataSet-Elemente angeben. Dies könnte nützlich sein, wenn Sie ein DataSet suchen, aber eine Liste von Datensätzen mit einem zweiten anzeigen möchten.
Eingabe- und Ausgabeeigenschaften festlegen
Zusätzlich zum DataSet können Sie Eingabe-Eigenschaften bereitstellen:
HighlightValue
: Erlaubt der die App erstellenden Person, einen Wert bereitzustellen, der mit der alsHighlightIndicator
property-set
festgelegten Spalte verglichen werden kann. Wenn die Werte gleich sind, sollte die Zeile hervorgehoben werden.HighlightColor
: Erlaubt der die App erstellenden Person, eine Farbe zum Hervorheben von Zeilen auszuwählen.
Tipp
Es wird empfohlen, Eingabeeigenschaften für die Gestaltung allgemeiner Aspekte Ihrer Codekomponenten bereitzustellen, wenn Sie Codekomponenten für die Verwendung in Canvas-Apps erstellen.
Neben den Eingabeeigenschaften wird eine Ausgabe-Eigenschaft namens FilteredRecordCount
aktualisiert (das das OnChange
-Ereignis auslöst), wenn die Zeilenanzahl aufgrund einer in der Codekomponente angewendeten Filteraktion geändert wird. Dies ist hilfreich, wenn Sie eine No Rows Found
-Nachricht in der übergeordneten App anzeigen lassen möchten.
Hinweis
In Zukunft unterstützen Codekomponenten benutzerdefinierte Ereignisse, sodass Sie ein bestimmtes Ereignis definieren können, anstatt das generische OnChange
-Ereignis zu verwenden.
Um diese drei Eigenschaften zu definieren, fügen Sie Folgendes zu der CanvasGrid\ControlManifest.Input.xml
-Datei unter dem data-set
-Element hinzu:
<property name="FilteredRecordCount"
display-name-key="FilteredRecordCount_Disp"
description-key="FilteredRecordCount_Desc"
of-type="Whole.None"
usage="output" />
<property name="HighlightValue"
display-name-key="HighlightValue_Disp"
description-key="HighlightValue_Desc"
of-type="SingleLine.Text"
usage="input"
required="true"/>
<property name="HighlightColor"
display-name-key="HighlightColor_Disp"
description-key="HighlightColor_Desc"
of-type="SingleLine.Text"
usage="input"
required="true"/>
Speichern Sie diese Datei und verwenden Sie dann in der Befehlszeile:
npm run build
Hinweis
Wenn beim Ausführen von npm run build
einen solcher Fehler zurückgegeben wird:
[2:48:57 PM] [build] Running ESLint...
[2:48:57 PM] [build] Failed:
[pcf-1065] [Error] ESLint validation error:
C:\repos\CanvasGrid\CanvasGrid\index.ts
2:47 error 'PropertyHelper' is not defined no-undef
Öffnen Sie die index.ts-Datei und fügen Sie direkt über der Zeile Folgendes hinzu: // eslint-disable-next-line no-undef
:
import DataSetInterfaces = ComponentFramework.PropertyHelper.DataSetApi;
Führen Sie npm run build
erneut aus.
Nachdem die Komponente erstellt wurde, sehen Sie Folgendes:
Eine automatisch generierte Datei
CanvasGrid\generated\ManifestTypes.d.ts
wird Ihrem Projekt hinzugefügt. Diese wird im Rahmen des Erstellen-Prozesses aus demControlManifest.Input.xml
und stellt die Typen für die Interaktion mit den Eingabe-/Ausgabeeigenschaften bereit.Die Erstellen-Ausgabe wird dem
out
-Ordner hinzugefügt. Dasbundle.js
ist das transpilierte JavaScript, das im Browser ausgeführt wird, und dieControlManifest.xml
ist eine neu formatierte Version derControlManifest.Input.xml
-Datei, die während der Bereitstellung verwendet wird.Hinweis
Ändern Sie die Inhalte der
generated
- undout
-Ordner nicht direkt. Sie werden im Rahmen des Build-Prozesses überschrieben.
Die „Grid Fluent UI React“-Komponente hinzufügen
Wenn die Codekomponente React verwendet, muss es eine einzelne Stammkomponente geben, die innerhalb der updateView-Methode gerendert wird. Innerhalb des CanvasGrid
-Ordners fügen Sie eine neue TypeScript-Datei mit dem Namen Grid.tsx
hinzu und den folgenden Inhalt hinzu:
import {
DetailsList,
ConstrainMode,
DetailsListLayoutMode,
IColumn,
IDetailsHeaderProps,
} from '@fluentui/react/lib/DetailsList';
import { Overlay } from '@fluentui/react/lib/Overlay';
import {
ScrollablePane,
ScrollbarVisibility
} from '@fluentui/react/lib/ScrollablePane';
import { Stack } from '@fluentui/react/lib/Stack';
import { Sticky } from '@fluentui/react/lib/Sticky';
import { StickyPositionType } from '@fluentui/react/lib/Sticky';
import { IObjectWithKey } from '@fluentui/react/lib/Selection';
import { IRenderFunction } from '@fluentui/react/lib/Utilities';
import * as React from 'react';
type DataSet = ComponentFramework.PropertyHelper.DataSetApi.EntityRecord & IObjectWithKey;
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<string, ComponentFramework.PropertyHelper.DataSetApi.EntityRecord>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
}
const onRenderDetailsHeader: IRenderFunction<IDetailsHeaderProps> = (props, defaultRender) => {
if (props && defaultRender) {
return (
<Sticky stickyPosition={StickyPositionType.Header} isScrollSynced>
{defaultRender({
...props,
})}
</Sticky>
);
}
return null;
};
const onRenderItemColumn = (
item?: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord,
index?: number,
column?: IColumn,
) => {
if (column && column.fieldName && item) {
return <>{item?.getFormattedValue(column.fieldName)}</>;
}
return <></>;
};
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
} = props;
const [isComponentLoading, setIsLoading] = React.useState<boolean>(false);
const items: (DataSet | undefined)[] = React.useMemo(() => {
setIsLoading(false);
const sortedRecords: (DataSet | undefined)[] = sortedRecordIds.map((id) => {
const record = records[id];
return record;
});
return sortedRecords;
}, [records, sortedRecordIds, hasNextPage, setIsLoading]);
const gridColumns = React.useMemo(() => {
return columns
.filter((col) => !col.isHidden && col.order >= 0)
.sort((a, b) => a.order - b.order)
.map((col) => {
const sortOn = sorting && sorting.find((s) => s.name === col.name);
const filtered =
filtering &&
filtering.conditions &&
filtering.conditions.find((f) => f.attributeName == col.name);
return {
key: col.name,
name: col.displayName,
fieldName: col.name,
isSorted: sortOn != null,
isSortedDescending: sortOn?.sortDirection === 1,
isResizable: true,
isFiltered: filtered != null,
data: col,
} as IColumn;
});
}, [columns, sorting]);
const rootContainerStyle: React.CSSProperties = React.useMemo(() => {
return {
height: height,
width: width,
};
}, [width, height]);
return (
<Stack verticalFill grow style={rootContainerStyle}>
<Stack.Item grow style={{ position: 'relative', backgroundColor: 'white' }}>
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
></DetailsList>
</ScrollablePane>
{(itemsLoading || isComponentLoading) && <Overlay />}
</Stack.Item>
</Stack>
);
});
Grid.displayName = 'Grid';
Hinweis
Die Datei hat die Erweiterung tsx
. Dies ist eine TypeScript-Datei, die die von React verwendete Syntax im XML-Stil unterstützt. Sie wird durch den Erstellenprozess in Standard-JavaScript kompiliert.
Anmerkungen zum Rasterdesign
Dieser Abschnitt enthält Anmerkungen zum Design der Grid.tsx
-Komponente.
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 {
DetailsList,
ConstrainMode,
DetailsListLayoutMode,
IColumn,
IDetailsHeaderProps,
Stack
} from "@fluentui/react";
Dieser Code verwendet Folgendes:
import {
DetailsList,
ConstrainMode,
DetailsListLayoutMode,
IColumn,
IDetailsHeaderProps,
} from '@fluentui/react/lib/DetailsList';
import { Stack } from '@fluentui/react/lib/Stack';
Dadurch wird Ihre Paketgröße kleiner, was zu geringeren Kapazitätsanforderungen und einer besseren Runtimeleistung führt.
Eine Alternative wäre Tree Shaking.
Destrukturierungszuweisung
Dieser Code:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
} = props;
Verwendet die 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.
Dieser Code verwendet darüber hinaus React.memo, um die Funktionskomponente so zu verpacken, dass sie nicht gerendert wird, es sei denn, die Eingabeeigenschaften werden geändert.
Verwendung von React.useMemo
React.useMemo wird an mehreren Stellen verwendet, 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.
Weitere zu beachtende Punkte:
- Die
DetailsList
in einemStack
wird verpackt, da Sie später ein Fußzeilenelement mit den Paging-Steuerelementen hinzufügen. - Die Fluent UI
Sticky
-Komponente wird verwendet, um die Kopfzeilenspalten (mitonRenderDetailsHeader
) zu verpacken, damit sie beim Scrollen des Rasters sichtbar bleiben. setKey
wird zusammen mitinitialFocusedIndex
anDetailsList
weitergeben, sodass beim Wechsel der aktuellen Seite die Bildlaufposition und Auswahl zurückgesetzt werden.- Die Funktion
onRenderItemColumn
wird verwendet, um den Zellinhalt zu rendern. Sie akzeptiert Zeilenelemente und verwendet getFormattedValue, um den Anzeigewert der Spalte zurückzugeben. Die getValue-Methode gibt einen Wert zurück, den Sie verwenden könnten, um ein alternatives Rendering bereitzustellen. Der Vorteil vongetFormattedValue
besteht darin, dass es eine formatierte Zeichenfolge für Spalten von Nicht-Zeichenfolgentypen wie Datumsangaben und Suchen enthält. - Der
gridColumns
-Block ordnet die Objektform der Spalten, die vom DataSet-Kontext bereitgestellt werden, der Form zu, die von derDetailsList
-Spalteneigenschaft erwartet wird. Da diese im React.useMemo-Hook verpackt ist, ändert sich die Ausgabe nur, wenn sich diecolumns
- odersorting
-Eigenschaften ändern. Sie können die Sortier- und Filtersymbole in den Spalten anzeigen, in denen die vom Codekomponentenkontext bereitgestellten Sortier- und Filterdetails mit der zugeordneten Spalte übereinstimmen. Die Spalten werden mit dercolumn.order
-Eigenschaft sortiert, um sicherzustellen, dass sie sich in der Reihenfolge im Raster befinden, die von der die App erstellende Person festgelegt wurde. - Sie erhalten einen internen Status für
isComponentLoading
in unserer React-Komponente. Dies liegt daran, dass Sie, wenn der Benutzer Sortier- und Filteraktionen auswählt, das Raster als visuellen Hinweis ausgrauen können, bis diesortedRecordIds
aktualisiert sind und der Status zurückgesetzt ist. Es gibt eine zusätzliche Eingabeeigenschaft namensitemsLoading
, die der dataset.loading -Eigenschaft zugeordnet ist, die vom DataSet-Kontext bereitgestellt wird. Beide Kennzeichen werden verwendet, um den visuellen Ladehinweis zu steuern, der mit der Fluent UIOverlay
-Komponente implementiert wird.
Index.ts aktualisieren
Der nächste Schritt besteht darin, Änderungen an der index.ts
-Datei vorzunehmen, um die in Grid.tsx.
festgelegten Eigenschaften abzugleichen
Importanweisungen hinzufügen und Symbole initialisieren
Ersetzen Sie die vorhandenen Importe durch Folgendes in der Kopfzeile von index.ts
:
import {IInputs, IOutputs} from './generated/ManifestTypes';
import DataSetInterfaces = ComponentFramework.PropertyHelper.DataSetApi;
type DataSet = ComponentFramework.PropertyTypes.DataSet;
Hinweis
Der Import von initializeIcons
ist erforderlich, da dieser Code den Fluent-Benutzeroberflächensymbolsatz verwendet. Sie rufen initializeIcons
auf, um die Symbole im Testkabelbaum zu laden. In Canvas-Apps sind sie bereits initialisiert.
Der CanvasGrid-Klasse Felder hinzufügen
Fügen Sie der CanvasGrid
-Klasse die folgenden Felder hinzu:
export class CanvasGrid implements ComponentFramework.StandardControl<IInputs, IOutputs> {
/**
* Empty constructor.
*/
constructor() {
}
Die init-Methode aktualisieren
Fügen Sie init
Folgendes hinzu:
public init(
context: ComponentFramework.Context<IInputs>,
notifyOutputChanged: () => void,
state: ComponentFramework.Dictionary,
container: HTMLDivElement): void {
// Add control initialization code
}
Die init
-Funktion wird aufgerufen, wenn die Codekomponente zum ersten Mal auf einem App-Bildschirm initialisiert wird. Sie speichern einen Verweis auf Folgendes:
notifyOutputChanged
: Dies ist der Rückruf, vorausgesetzt, der Aufruf dient dazu, die Canvas-App zu benachrichtigen, dass sich eine der Eigenschaften geändert hat.container
: Dies ist das DOM-Element, dem Sie Ihre Codekomponenten-UI hinzufügen.resources
: Dies wird verwendet, um lokalisierte Zeichenfolgen in der Sprache des aktuellen Benutzers abzurufen.
context.mode.trackContainerResize(true)) wird verwendet, damit updateView
aufgerufen wird, wenn die Codekomponente die Größe ändert.
Hinweis
Derzeit gibt es keine Möglichkeit, festzustellen, ob die Codekomponente innerhalb der Testumgebung ausgeführt wird. Sie müssen feststellen, ob das control-dimensions
div
-Element als Indikator vorhanden ist.
Die updateView-Methode aktualisieren
Fügen Sie updateView
Folgendes hinzu:
public updateView(context: ComponentFramework.Context<IInputs>): void {
// Add code to update control view
}
Sie sehen, dass:
- Sie rufen React.createElement ab und übergeben den Verweis auf den DOM-Container, den Sie in der
init
-Funktion erhalten haben. - Die
Grid
-Komponente ist inGrid.tsx
definiert und wird am Anfang der Datei importiert. allocatedWidth
undallocatedHeight
werden vom übergeordneten Kontext bereitgestellt, wenn sie sich ändern (z. B. wenn die App die Größe der Codekomponente ändert oder Sie in den Vollbildmodus wechseln), nachdem Sie einen Aufruf an trackContainerResize(true) in derinit
-Funktion gemacht haben.- Sie können erkennen, wann neue Zeilen angezeigt werden müssen, wenn die updatedProperties-Array die
dataset
-Zeichenfolge enthält. - In der Testumgebung ist das
updatedProperties
-Array nicht ausgefüllt, Sie können also dasisTestHarness
-Kennzeichen verwenden, das Sie in derinit
-Funktion zum Kurzschließen der Logik festlegen, diesortedRecordId
undrecords
bestimmt. Sie behalten einen Verweis auf die aktuellen Werte, bis sie sich ändern, damit Sie diese bei der Übergabe an die untergeordnete Komponente nicht ändern, es sei denn, die Daten müssen erneut gerendert werden. - Da die Codekomponente den Status der angezeigten Seite beibehält, wird die Seitennummer zurückgesetzt, wenn der übergeordnete Kontext die Datensätze auf die erste Seite zurücksetzt. Sie wissen, wann Sie wieder auf der ersten Seite sind, wenn
hasPreviousPage
falsch ist.
Die destroy-Methode aktualisieren
Schließlich müssen Sie eine Bereinigung durchführen, wenn die Codekomponente zerstört wird:
Die Testumgebung starten
Stellen Sie sicher, dass alle Dateien gespeichert sind und am Terminal verwendet werden:
npm start watch
Sie müssen die Breite und Höhe festlegen, um das Codekomponentenraster anzuzeigen, das mit den drei Beispieldatensätzen ausgefüllt wird. Sie können dann eine Reihe von Datensätzen in eine CSV-Datei aus Dataverse exportieren und dann mit in der Testumgebung mit Dateneingaben > Datensatzbereich laden:
Hier sind einige durch Kommas getrennte Beispieldaten, die Sie in einer .csv-Datei speichern und verwenden können:
address1_city,address1_country,address1_stateorprovince,address1_line1,address1_postalcode,telephone1,emailaddress1,firstname,fullname,jobtitle,lastname
Seattle,U.S.,WA,7842 Ygnacio Valley Road,12150,555-0112,someone_m@example.com,Thomas,Thomas Andersen (sample),Purchasing Manager,Andersen (sample)
Renton,U.S.,WA,7165 Brock Lane,61795,555-0109,someone_j@example.com,Jim,Jim Glynn (sample),Owner,Glynn (sample)
Snohomish,U.S.,WA,7230 Berrellesa Street,78800,555-0106,someone_g@example.com,Robert,Robert Lyon (sample),Owner,Lyon (sample)
Seattle,U.S.,WA,931 Corte De Luna,79465,555-0111,someone_l@example.com,Susan,Susan Burk (sample),Owner,Burk (sample)
Seattle,U.S.,WA,7765 Sunsine Drive,11910,555-0110,someone_k@example.com,Patrick,Patrick Sands (sample),Owner,Sands (sample)
Seattle,U.S.,WA,4948 West Th St,73683,555-0108,someone_i@example.com,Rene,Rene Valdes (sample),Purchasing Assistant,Valdes (sample)
Redmond,U.S.,WA,7723 Firestone Drive,32147,555-0107,someone_h@example.com,Paul,Paul Cannon (sample),Purchasing Assistant,Cannon (sample)
Issaquah,U.S.,WA,989 Caravelle Ct,33597,555-0105,someone_f@example.com,Scott,Scott Konersmann (sample),Purchasing Manager,Konersmann (sample)
Issaquah,U.S.,WA,7691 Benedict Ct.,57065,555-0104,someone_e@example.com,Sidney,Sidney Higa (sample),Owner,Higa (sample)
Monroe,U.S.,WA,3747 Likins Avenue,37925,555-0103,someone_d@example.com,Maria,Maria Campbell (sample),Purchasing Manager,Campbell (sample)
Duvall,U.S.,WA,5086 Nottingham Place,16982,555-0102,someone_c@example.com,Nancy,Nancy Anderson (sample),Purchasing Assistant,Anderson (sample)
Issaquah,U.S.,WA,5979 El Pueblo,23382,555-0101,someone_b@example.com,Susanna,Susanna Stubberod (sample),Purchasing Manager,Stubberod (sample)
Redmond,U.S.,WA,249 Alexander Pl.,86372,555-0100,someone_a@example.com,Yvonne,Yvonne McKay (sample),Purchasing Manager,McKay (sample)
Hinweis
In der Testumgebung wird nur eine einzige Spalte angezeigt, unabhängig von den Spalten, die Sie in der geladenen CSV-Datei angeben. Dies liegt daran, dass die Testumgebung nur dann property-set
anzeigt, wenn einer definiert ist. Wenn kein property-set
definiert ist, werden alle Spalten in der geladenen CSV-Datei aufgefüllt.
Zeichenauswahl hinzufügen
Obwohl die Fluent UI DetailsList
standardmäßig die Auswahl von Datensätzen erlaubt, sind die ausgewählten Datensätze nicht mit der Ausgabe der Codekomponente verknüpft. Sie brauchen die Selected
- und SelectedItems
-Eigenschaften, um die ausgewählten Datensätze in einer Canvas-App widerzuspiegeln, sodass dazugehörende Komponenten aktualisiert werden können. In diesem Beispiel erlauben Sie jeweils nur die Auswahl eines einzelnen Elements, sodass SelectedItems
immer nur einen einzigen Datensatz enthält.
Grid.tsx-Importe aktualisieren
Fügen Sie den Importen in Grid.tsx
Folgendes hinzu:
import {
DetailsList,
ConstrainMode,
DetailsListLayoutMode,
IColumn,
IDetailsHeaderProps,
} from '@fluentui/react/lib/DetailsList';
import { Overlay } from '@fluentui/react/lib/Overlay';
import {
ScrollablePane,
ScrollbarVisibility
} from '@fluentui/react/lib/ScrollablePane';
import { Stack } from '@fluentui/react/lib/Stack';
import { Sticky } from '@fluentui/react/lib/Sticky';
import { StickyPositionType } from '@fluentui/react/lib/Sticky';
import { IObjectWithKey } from '@fluentui/react/lib/Selection';
import { IRenderFunction } from '@fluentui/react/lib/Utilities';
import * as React from 'react';
SetSelectedRecords zu GridProps hinzufügen
Fügen Sie der GridProps
-Schnittstelle in Grid.tsx
Folgendes hinzu:
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<string, ComponentFramework.PropertyHelper.DataSetApi.EntityRecord>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
}
Die setSelectedRecords-Eigenschaft zum Raster hinzufügen
Aktualisieren Sie in der Grid.tsx
-Funktionskomponente die Destrukturierung der props
, um die neue Eigenschaft setSelectedRecords
hinzuzufügen.
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
} = props;
Fügen Sie direkt darunter Folgendes hinzu:
const forceUpdate = useForceUpdate();
const onSelectionChanged = React.useCallback(() => {
const items = selection.getItems() as DataSet[];
const selected = selection.getSelectedIndices().map((index: number) => {
const item: DataSet | undefined = items[index];
return item && items[index].getRecordId();
});
setSelectedRecords(selected);
forceUpdate();
}, [forceUpdate]);
const selection: Selection = useConst(() => {
return new Selection({
selectionMode: SelectionMode.single,
onSelectionChanged: onSelectionChanged,
});
});
Die React.useCallback- und die useConst-Hooks werden verwendet, um sicherzustellen, dass diese Werte zwischen Renderings nicht mutieren und kein unnötiges Rendering untergeordneter Komponenten verursachen.
Der useForceUpdate-Hook stellt sicher, dass beim Aktualisieren der Auswahl die Komponente neu gerendert wird, um die aktualisierte Auswahlanzahl widerzuspiegeln.
Auswahl zur DetailsList hinzufügen
Das zur Beibehaltung des Auswahlstaatus erstellte selection
-Objekt wird dann an die DetailsList
-Komponente übergeben:
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
></DetailsList>
Den setSelectedRecords-Rückruf definieren
Sie müssen den neuen setSelectedRecords
-Rückruf in index.ts
festlegen und an die Grid
-Komponente übergeben. Fügen Sie oben auf der CanvasGrid
-Klasse Folgendes hinzu:
export class CanvasGrid
implements ComponentFramework.StandardControl<IInputs, IOutputs>
{
notifyOutputChanged: () => void;
container: HTMLDivElement;
context: ComponentFramework.Context<IInputs>;
sortedRecordsIds: string[] = [];
resources: ComponentFramework.Resources;
isTestHarness: boolean;
records: {
[id: string]: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord;
};
currentPage = 1;
filteredRecordCount?: number;
Hinweis
Die Methode ist als Pfeilfunktion festgelegt, um sie an die aktuelle this
-Instanz der Codekomponente zu binden.
Der Aufruf an setSelectedRecordIds informiert die Canvas-App, dass sich die Auswahl geändert hat, sodass andere auf SelectedItems
und Selected
verweisenden Komponenten aktualisiert werden.
Fügen Sie den Eingabeeigenschaften einen neuen Rückruf hinzu
Fügen Sie schließlich den neuen Rückruf den Eingabeeigenschaften der Grid
-Komponente in der updateView
-Methode hinzu:
ReactDOM.render(
React.createElement(Grid, {
width: allocatedWidth,
height: allocatedHeight,
columns: dataset.columns,
records: this.records,
sortedRecordIds: this.sortedRecordsIds,
hasNextPage: paging.hasNextPage,
hasPreviousPage: paging.hasPreviousPage,
currentPage: this.currentPage,
totalResultCount: paging.totalResultCount,
sorting: dataset.sorting,
filtering: dataset.filtering && dataset.filtering.getFilter(),
resources: this.resources,
itemsLoading: dataset.loading,
highlightValue: this.context.parameters.HighlightValue.raw,
highlightColor: this.context.parameters.HighlightColor.raw,
}),
this.container
);
Das OnSelect
-Ereignis aufrufen
Es gibt ein Muster in Canvas-Apps, bei dem, wenn ein Katalog oder ein Raster eine Elementauswahl aufgerufen hat (z. B. Auswahl eines Chevron-Symbols), ein OnSelect
-Ereignis aufgerufen wird. Sie können dieses Muster mit der openDatasetItem-Methode des DataSet implementieren.
OnNavigate zur GridProps-Schnittstelle hinzufügen
Wie zuvor fügen Sie eine zusätzliche Rückrufeigenschaft auf der Grid
-Komponente hinzu, indem Sie Folgendes zu der GridProps
-Schnittstelle in Grid.tsx
hinzufügen:
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<
string,
ComponentFramework.PropertyHelper.DataSetApi.EntityRecord
>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
setSelectedRecords: (ids: string[]) => void;
}
OnNavigate zu Rastereigenschaften hinzufügen
Auch hier müssen Sie die neue Eigenschaft der Destrukturierung der Eigenschaften hinzufügen:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
setSelectedRecords,
} = props;
OnItemInvoked zur DetailsList hinzufügen
Die DetailList
hat eine Rückrufeigenschaft namens onItemInvoked
, an die Sie Ihren Rückruf wiederum weiterleiten:
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
selection={selection}
></DetailsList>
OnNavigate-Methode zu index.ts hinzufügen
Ergänzen Sie die onNavigate
-Methode zum index.ts
direkt unter der setSelectedRecords
-Methode:
onNavigate = (
item?: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord
): void => {
if (item) {
this.context.parameters.records.openDatasetItem(item.getNamedReference());
}
};
Dies ruft einfach die openDatasetItem
-Methode für den DataSet-Datensatz auf, damit die Codekomponente das OnSelect
-Ereignis auslöst. Die Methode ist als Pfeilfunktion festgelegt, um sie an die aktuelle this
-Instanz der Codekomponente zu binden.
Sie müssen diesen Rückruf an die Grid
-Komponenteneigenschaften in der updateView
-Methode übergeben:
ReactDOM.render(
React.createElement(Grid, {
width: allocatedWidth,
height: allocatedHeight,
columns: dataset.columns,
records: this.records,
sortedRecordIds: this.sortedRecordsIds,
hasNextPage: paging.hasNextPage,
hasPreviousPage: paging.hasPreviousPage,
currentPage: this.currentPage,
totalResultCount: paging.totalResultCount,
sorting: dataset.sorting,
filtering: dataset.filtering && dataset.filtering.getFilter(),
resources: this.resources,
itemsLoading: dataset.loading,
highlightValue: this.context.parameters.HighlightValue.raw,
highlightColor: this.context.parameters.HighlightColor.raw,
setSelectedRecords: this.setSelectedRecords,
}),
this.container
);
Wenn Sie alle Dateien speichern, wird die Testumgebung neu geladen. Verwenden Sie Ctrl
+ Shift
+ I
(oder F12
) und Datei öffnen (Ctrl
+ P
) für die Suche nach index.ts
und Sie können einen Haltepunkt in der onNavigate
-Methode platzieren. Machen Sie einen Doppelklick auf eine Zeile (oder markieren Sie sie mit den Cursortasten und Enter
) und der Haltepunkt erreicht, da die DetailsList
einen onNavigate
-Rückruf auslöst.
Es gibt einen Verweis auf _this
, weil die Funktion als Pfeilfunktion festgelegt und in einen JavaScript-Abschluss transpiliert wurde, um die Instanz von this
zu erfassen.
Lokalisierung hinzufügen
Bevor Sie fortfahren, müssen Sie der Codekomponente Ressourcenzeichenfolgen hinzufügen, damit Sie lokalisierte Zeichenfolgen für Nachrichten wie Paging, Sortierung und Filtern verwenden können. Fügen Sie eine neue Datei CanvasGrid\strings\CanvasGrid.1033.resx
hinzu und verwenden Sie den Visual Studio Ressourcen-Editor oder Visual Studio Code mit einer Erweiterung, um Folgendes einzugeben:
Name des Dataflows | Wert |
---|---|
Records_Dataset_Display |
Einträge |
FilteredRecordCount_Disp |
Gefilterte Datensatzanzahl |
FilteredRecordCount_Desc |
Die Anzahl der Datensätze nach der Filterung |
HighlightValue_Disp |
Hervorhebenwert |
HighlightValue_Desc |
Der Wert, der angibt, dass eine Zeile hervorgehoben werden sollte |
HighlightColor_Disp |
Hervorhebungsfarbe |
HighlightColor_Desc |
Die Farbe zum Hervorheben einer Zeile |
HighlightIndicator_Disp |
Hervorhebenanzeige-Feld |
HighlightIndicator_Desc |
Legen Sie den Namen des Felds fest, das mit dem Hervorhebenwert verglichen werden soll |
Label_Grid_Footer |
Seite {0} ({1} ausgewählt) |
Label_SortAZ |
A bis Z |
Label_SortZA |
Z bis A |
Label_DoesNotContainData |
Enthält keine Daten |
Label_ShowFullScreen |
Vollbild anzeigen |
Tipp
Es wird nicht empfohlen, resx
-Dateien direkt zu bearbeiten. Verwenden Sie stattdessen entweder den Ressourcen-Editor von Visual Studio oder eine Erweiterung für Visual Studio Code. So finden Sie eine Erweiterung des Visual Studio Codes: In Visual Studio Marketplace nach einem resx-Editor suchen
Die Daten für diese Datei können auch eingestellt werden, indem Sie die CanvasGrid.1033.resx
-Datei in Notepad öffnen und den folgenden XML-Inhalt kopieren:
<?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="Records_Dataset_Display" xml:space="preserve">
<value>Records</value>
</data>
<data name="FilteredRecordCount_Disp" xml:space="preserve">
<value>Filtered Record Count</value>
</data>
<data name="FilteredRecordCount_Desc" xml:space="preserve">
<value>The number of records after filtering</value>
</data>
<data name="HighlightValue_Disp" xml:space="preserve">
<value>Highlight Value</value>
</data>
<data name="HighlightValue_Desc" xml:space="preserve">
<value>The value to indicate a row should be highlighted</value>
</data>
<data name="HighlightColor_Disp" xml:space="preserve">
<value>Highlight Color</value>
</data>
<data name="HighlightColor_Desc" xml:space="preserve">
<value>The color to highlight a row using</value>
</data>
<data name="HighlightIndicator_Disp" xml:space="preserve">
<value>Highlight Indicator Field</value>
</data>
<data name="HighlightIndicator_Desc" xml:space="preserve">
<value>Set to the name of the field to compare against the Highlight Value</value>
</data>
<data name="Label_Grid_Footer" xml:space="preserve">
<value>Page {0} ({1} Selected)</value>
</data>
<data name="Label_SortAZ" xml:space="preserve">
<value>A to Z</value>
</data>
<data name="Label_SortZA" xml:space="preserve">
<value>Z to A</value>
</data>
<data name="Label_DoesNotContainData" xml:space="preserve">
<value>Does not contain data</value>
</data>
<data name="Label_ShowFullScreen" xml:space="preserve">
<value>Show Full Screen</value>
</data>
</root>
Sie haben Ressourcenzeichenfolgen für die input
/output
-Eigenschaften und das dataset
und den verbundenen property-set
. Diese werden bei der Entwurfszeit in Power Apps Studio basierend auf der Browsersprache des Herstellers verwendet. Sie können auch Beschriftungszeichenfolgen hinzufügen, die zur Ruftime mithilfe von getString abgerufen werden. Weitere Informationen: Implementieren der Lokalisierungs-API-Komponente.
Fügen sie diese neue Ressourcendatei der ControlManifest.Input.xml
-Datei im resources
-Element hinzu:
Spaltensortierung und -filterung hinzufügen
Wenn Sie dem Benutzer das Sortieren und Filtern mithilfe von Rasterspaltenüberschriften ermöglichen möchten, bietet die Fluent-Benutzeroberfläche DetailList
eine einfache Möglichkeit, den Spaltenüberschriften Kontextmenüs hinzuzufügen.
OnSort und onFilter zu GridProps hinzufügen
Zuerst fügen Sie der GridProps
-Schnittstelle in Grid.tsx
onSort
und onFilter
hinzu, um Rückruffunktionen zum Sortieren und Filtern bereitzustellen:
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<
string,
ComponentFramework.PropertyHelper.DataSetApi.EntityRecord
>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
setSelectedRecords: (ids: string[]) => void;
onNavigate: (
item?: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord
) => void;
}
OnSort, onFilter und Ressourcen zu Eigenschaften hinzufügen
Fügen Sie dann diese neuen Eigenschaften zusammen mit dem resources
-Verweis (damit Sie lokalisierte Beschriftungen zum Sortieren und Filtern abrufen können) auf die Destrukturierung der Eigenschaften hinzu:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
setSelectedRecords,
onNavigate,
} = props;
ContextualMenu-Komponenten importieren
Sie müssen einige Importe am Anfang Grid.tsx
hinzufügen, damit Sie die ContextualMenu
-Komponente, die von Fluent UI bereitgestellt wird, verwenden können. Sie können die pfadbasierten Importe verwenden, um die Paketgröße zu reduzieren.
import { ContextualMenu, DirectionalHint, IContextualMenuProps } from '@fluentui/react/lib/ContextualMenu';
Rendering-Funktionalität für Kontextmenüs hinzufügen
Fügen Sie nun die Kontextmenü-Rendering-Funktionalität zu Grid.tsx
direkt unter dieser Zeile hinzu
const [isComponentLoading, setIsLoading] = React.useState<boolean>(false);
:
Sie sehen, dass:
- Der
contextualMenuProps
-Status steuert die Sichtbarkeit des Kontextmenüs, das mit der Fluent-BenutzeroberflächenkomponenteContextualMenu
gerendert wird. - Dieser Code stellt einen einfachen Filter bereit, um nur Werte anzuzeigen, bei denen das Feld keine Daten enthält. Sie können dies erweitern, um zusätzliche Filter bereitzustellen.
- Dieser Code verwendet
resources.getString
, um Beschriftungen im Kontextmenü anzuzeigen, die lokalisiert werden können. - Der
React.useCallback
-Hook stellt auf ähnliche Art und Weise wieReact.useMemo
sicher, dass die Rückrufe nur mutiert werden, wenn sich die abhängigen Werte ändern. Dadurch wird das Rendering von untergeordneten Komponenten optimiert.
Fügen Sie neuen Kontextmenüfunktionen zu den Spaltenauswahl- und Kontextmenüereignissen hinzu
Fügen Sie diese neuen Kontextmenüfunktionen zu den Spaltenauswahl- und Kontextmenüereignissen hinzu. Aktualisieren Sie const gridColumns
, um die onColumnContextMenu
- und onColumnClick
-Rückrufe hinzuzufügen:
const gridColumns = React.useMemo(() => {
return columns
.filter((col) => !col.isHidden && col.order >= 0)
.sort((a, b) => a.order - b.order)
.map((col) => {
const sortOn = sorting && sorting.find((s) => s.name === col.name);
const filtered =
filtering &&
filtering.conditions &&
filtering.conditions.find((f) => f.attributeName == col.name);
return {
key: col.name,
name: col.displayName,
fieldName: col.name,
isSorted: sortOn != null,
isSortedDescending: sortOn?.sortDirection === 1,
isResizable: true,
isFiltered: filtered != null,
data: col,
} as IColumn;
});
}, [columns, sorting]);
Kontextmenü zur gerenderten Ausgabe hinzufügen
Damit das Kontextmenü angezeigt wird, müssen Sie es der gerenderten Ausgabe hinzufügen. Fügen Sie Folgendes direkt unter der DetailsList
-Komponente in der zurückgegebenen Ausgabe hinzu:
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
selection={selection}
onItemInvoked={onNavigate}
></DetailsList>
</ScrollablePane>
Die Funktionen onSort und OnFilter hinzufügen
Nachdem Sie nun die Sortier- und Filterbenutzeroberfläche hinzugefügt haben, müssen Sie die Rückrufe zu index.ts
hinzufügen, um das Sortieren und Filtern der Datensätze durchzuführen, die an die Codekomponente gebunden sind. Fügen Sie Folgendes zu index.ts
direkt unter der onNavigate
-Funktion hinzu:
onSort = (name: string, desc: boolean): void => {
const sorting = this.context.parameters.records.sorting;
while (sorting.length > 0) {
sorting.pop();
}
this.context.parameters.records.sorting.push({
name: name,
sortDirection: desc ? 1 : 0,
});
this.context.parameters.records.refresh();
};
onFilter = (name: string, filter: boolean): void => {
const filtering = this.context.parameters.records.filtering;
if (filter) {
filtering.setFilter({
conditions: [
{
attributeName: name,
conditionOperator: 12, // Does not contain Data
},
],
} as ComponentFramework.PropertyHelper.DataSetApi.FilterExpression);
} else {
filtering.clearFilter();
}
this.context.parameters.records.refresh();
};
Sie sehen, dass:
- Die Sortierung und der Filter werden dem DataSet mit den Eigenschaften Sortieren und Filterung angewendet.
- Beim Ändern der Sortierspalten müssen die vorhandenen Sortierdefinitionen mithilfe von Pop entfernt und nicht das Sortierarray selbst ersetzt werden.
- Nach der Anwendung von Sortieren und Filtern muss Aktualisieren aufgerufen werden. Wenn ein Filter und eine Sortierung gleichzeitig angewendet werden, muss „Aktualisieren“ nur einmal aufgerufen werden.
OnSort- und OnFilter-Rückrufe zum Rasterrendering hinzufügen
Schließlich können Sie diese beiden Rückrufe an den Grid
-Rendering-Aufruf übergeben:
ReactDOM.render(
React.createElement(Grid, {
width: allocatedWidth,
height: allocatedHeight,
columns: dataset.columns,
records: this.records,
sortedRecordIds: this.sortedRecordsIds,
hasNextPage: paging.hasNextPage,
hasPreviousPage: paging.hasPreviousPage,
currentPage: this.currentPage,
totalResultCount: paging.totalResultCount,
sorting: dataset.sorting,
filtering: dataset.filtering && dataset.filtering.getFilter(),
resources: this.resources,
itemsLoading: dataset.loading,
highlightValue: this.context.parameters.HighlightValue.raw,
highlightColor: this.context.parameters.HighlightColor.raw,
setSelectedRecords: this.setSelectedRecords,
onNavigate: this.onNavigate,
}),
this.container
);
Hinweis
An dieser Stelle können Sie nicht mehr mit der Testumgebung testen, da sie keine Unterstützung für das Sortieren und Filtern bietet. Später können Sie mithilfe von pac pcf push bereitstellen und dann zum Testen zu einer Canvas-App hinzufügen. Wenn Sie möchten, können Sie mit diesem Schritt fortfahren, um zu sehen, wie die Codekomponente in Canvas-Apps aussieht.
Die Ausgabeeigenschaft FilteredRecordCount aktualisieren
Da das Raster jetzt Datensätze intern filtern kann, ist es wichtig, der Canvas-App zu melden, wie viele Datensätze angezeigt werden. Auf diese Weise können Sie eine Meldung vom Typ „Keine Datensätze“ anzeigen.
Tipp
Sie können dies intern in der Codekomponente implementieren, es wird jedoch empfohlen, der Canvas-App so viel Benutzeroberfläche zu überlassen, da dies der die App erstellenden Person mehr Flexibilität bietet.
Sie haben bereits eine Ausgabeeigenschaft namens FilteredRecordCount
im ControlManifest.Input.xml
festgelegt. Wenn die Filterung durchgeführt wird und die gefilterten Datensätze geladen werden, wird die updateView
-Funktion mit dem Zeichenfolgen-dataset
updatedProperties-Array aufgerufen. Wenn sich die Anzahl der Datensätze geändert hat, müssen Sie notifyOutputChanged
aufrufen, damit die Canvas-App weiß, dass sie alle Steuerelemente aktualisieren muss, die die FilteredRecordCount
-Eigenschaft verwenden. Fügen Sie in der updateView
-Methode von index.ts
Folgendes direkt über dem ReactDOM.render
und unter dem allocatedHeight
hinzu:
FilteredRecordCount zu getOutputs hinzufügen
Dadurch wird der filteredRecordCount
auf der Codekomponentenklasse aktualisiert, die Sie vorher definiert haben, wenn sie sich von den neu empfangenen Daten unterscheidet. Nachdem notifyOutputChanged
aufgerufen wurde, müssen Sie sicherstellen, dass der Wert zurückgegeben wird, wenn getOutputs
aufgerufen wird. Aktualisieren Sie die getOutputs
-Methode also auf:
Paging zum Raster hinzufügen
Bei großen Datasets teilen Canvas-Apps die Datensätze auf mehrere Seiten auf. Sie können eine Fußzeile hinzufügen, die Steuerelemente für die Seitennavigation anzeigt. Jede Schaltfläche wird mit einer Fluent-Benutzeroberflächen IconButton
gerendert, die Sie importieren müssen.
IconButton zu Importen hinzufügen
Fügen Sie diese den Importen in Grid.tsx
hinzu:
import { IconButton } from '@fluentui/react/lib/Button';
StringFormat-Funktion hinzufügen
Der folgende Schritt führt Funktionsweisen hinzu, um das Format für die Seitenindikatorbeschriftung aus den Ressourcenzeichenfolgen ("Page {0} ({1} Selected)"
) hinzuzufügen und mit einer einfachen Funktion stringFormat
-Funktion zu formatieren. Diese Funktion könnte sich gleichermaßen in einer separaten Datei befinden und der Einfachheit halber zwischen Ihren Komponenten geteilt werden:
Fügen Sie es in diesem Tutorial oben in Grid.tsx
direkt unter type DataSet ...
hinzu.
function stringFormat(template: string, ...args: string[]): string {
for (const k in args) {
template = template.replace("{" + k + "}", args[k]);
}
return template;
}
Paging-Schaltflächen hinzufügen
Fügen Sie in Grid.tsx
das folgende Stack.Item
unter dem vorhandenen Stack.Item
hinzu, das den ScrollablePane
enthält:
return (
<Stack verticalFill grow style={rootContainerStyle}>
<Stack.Item grow style={{ position: 'relative', backgroundColor: 'white' }}>
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
selection={selection}
onItemInvoked={onNavigate}
></DetailsList>
{contextualMenuProps && <ContextualMenu {...contextualMenuProps} />}
</ScrollablePane>
{(itemsLoading || isComponentLoading) && <Overlay />}
</Stack.Item>
</Stack>
);
Sie sehen, dass:
- Der
Stack
stellt sicher, dass die Fußzeile unterhalb derDetailsList
erscheint. Dasgrow
-Attribut wird verwendet, um sicherzustellen, dass das Raster erweitert wird, um den verfügbaren Platz auszufüllen. - Sie laden das Format für die Seitenindikatorbeschriftung aus den Ressourcenzeichenfolgen (
"Page {0} ({1} Selected)"
) und nehmen Sie die Formatierung mit derstringFormat
-Funktion hinzu, die Sie im letzten Schritt hinzugefügt haben. - Sie können
alt
-Text für Barrierefreiheit auf den Paging-IconButtons
bereitstellen. - Der Stil in der Fußzeile kann auch mit einem CSS-Klassennamen verwendet werden, der auf eine CSS-Datei zur Codekomponente hinzugefügt wird.
Rückrufeigenschaften zur Unterstützung von Paging hinzufügen
Als Nächstes müssen Sie die fehlenden loadFirstPage
-, loadNextPage
- und loadPreviousPage
-Rückrufeigenschaften hinzufügen.
Fügen Sie der GridProps
-Schnittstelle Folgendes hinzu:
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<string, ComponentFramework.PropertyHelper.DataSetApi.EntityRecord>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
setSelectedRecords: (ids: string[]) => void;
onNavigate: (item?: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord) => void;
onSort: (name: string, desc: boolean) => void;
onFilter: (name: string, filtered: boolean) => void;
}
Neue Pagingeigenschaften dem Raster hinzufügen
Fügen Sie diese neuen Eigenschaften zu den Eigenschaften zur Destrukturierung hinzu:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
setSelectedRecords,
onNavigate,
onSort,
onFilter,
resources,
} = props;
Rückrufe zu index.ts hinzufügen
Fügen Sie diese Rückrufe zu index.ts
unterhalb der onFilter
-Methode hinzu:
loadFirstPage = (): void => {
this.currentPage = 1;
this.context.parameters.records.paging.loadExactPage(1);
};
loadNextPage = (): void => {
this.currentPage++;
this.context.parameters.records.paging.loadExactPage(this.currentPage);
};
loadPreviousPage = (): void => {
this.currentPage--;
this.context.parameters.records.paging.loadExactPage(this.currentPage);
};
Aktualisieren Sie dann den Grid
Renderingaufruf, um diese Rückrufe einzuschließen:
ReactDOM.render(
React.createElement(Grid, {
width: allocatedWidth,
height: allocatedHeight,
columns: dataset.columns,
records: this.records,
sortedRecordIds: this.sortedRecordsIds,
hasNextPage: paging.hasNextPage,
hasPreviousPage: paging.hasPreviousPage,
currentPage: this.currentPage,
totalResultCount: paging.totalResultCount,
sorting: dataset.sorting,
filtering: dataset.filtering && dataset.filtering.getFilter(),
resources: this.resources,
itemsLoading: dataset.loading,
highlightValue: this.context.parameters.HighlightValue.raw,
highlightColor: this.context.parameters.HighlightColor.raw,
setSelectedRecords: this.setSelectedRecords,
onNavigate: this.onNavigate,
onSort: this.onSort,
onFilter: this.onFilter,
}),
this.container
);
Vollbildunterstützung hinzufügen
Codekomponenten bieten die Möglichkeit, im Vollbildmodus anzuzeigen. Dies ist besonders nützlich bei kleinen Bildschirmgrößen oder wenn der Platz für die Codekomponente innerhalb eines Canvas-App-Bildschirms begrenzt ist.
Fluent-Benutzeroberflächen-Link-Komponente hinzufügen
Um den Vollbildmodus zu starten, können Sie die Link
-Komponente der Fluent-Benutzeroberfläche verwenden. Fügen Sie sie zu den Importen oben in Grid.tsx
hinzu:
import { Link } from '@fluentui/react/lib/Link';
Das Link-Steuerelement hinzufügen
Um einen Vollbild-Link hinzuzufügen, fügen Sie Folgendes zum vorhandenen Stack
hinzu, der die Paging-Steuerelemente enthält.
Hinweis
Achten Sie darauf, dies zu dem verschachtelten Stack
hinzuzufügen, und nicht dem Stamm-Stack
.
<Stack horizontal style={{ width: '100%', paddingLeft: 8, paddingRight: 8 }}>
<IconButton
alt="First Page"
iconProps={{ iconName: 'Rewind' }}
disabled={!hasPreviousPage}
onClick={loadFirstPage}
/>
<IconButton
alt="Previous Page"
iconProps={{ iconName: 'Previous' }}
disabled={!hasPreviousPage}
onClick={loadPreviousPage}
/>
<Stack.Item align="center">
{stringFormat(
resources.getString('Label_Grid_Footer'),
currentPage.toString(),
selection.getSelectedCount().toString(),
)}
</Stack.Item>
<IconButton
alt="Next Page"
iconProps={{ iconName: 'Next' }}
disabled={!hasNextPage}
onClick={loadNextPage}
/>
</Stack>
Sie sehen, dass:
- Dieser Code verwendet Ressourcen, um die Beschriftung anzuzeigen, um die Lokalisierung zu unterstützen.
- Wenn der Vollbildmodus geöffnet ist, wird der Link nicht angezeigt. Stattdessen rendert der Kontext der übergeordneten App automatisch ein Schließensymbol.
Eigenschaften zur Unterstützung des Vollbildmodus zu GridProps hinzufügen
Fügen Sie die Eigenschaften onFullScreen
und isFullScreen
zur GridProps
-Schnittstelle in Grid.tsx
hinzu, um Rückruffunktionen zum Sortieren und Filtern bereitzustellen:
export interface GridProps {
width?: number;
height?: number;
columns: ComponentFramework.PropertyHelper.DataSetApi.Column[];
records: Record<string, ComponentFramework.PropertyHelper.DataSetApi.EntityRecord>;
sortedRecordIds: string[];
hasNextPage: boolean;
hasPreviousPage: boolean;
totalResultCount: number;
currentPage: number;
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
filtering: ComponentFramework.PropertyHelper.DataSetApi.FilterExpression;
resources: ComponentFramework.Resources;
itemsLoading: boolean;
highlightValue: string | null;
highlightColor: string | null;
setSelectedRecords: (ids: string[]) => void;
onNavigate: (item?: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord) => void;
onSort: (name: string, desc: boolean) => void;
onFilter: (name: string, filtered: boolean) => void;
loadFirstPage: () => void;
loadNextPage: () => void;
loadPreviousPage: () => void;
}
Eigenschaften zur Unterstützung des Vollbildmodus dem Raster hinzufügen
Fügen Sie diese neuen Eigenschaften zu den Eigenschaften zur Destrukturierung hinzu:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
setSelectedRecords,
onNavigate,
onSort,
onFilter,
resources,
loadFirstPage,
loadNextPage,
loadPreviousPage,
} = props;
Index.ts zur Unterstützung des Vollbildmodus für das Raster aktualisieren
Um diese neuen Eigenschaften bereitzustellen, fügen wir in index.ts
die folgende Rückrufmethode unter loadPreviousPage
hinzu:
onFullScreen = (): void => {
this.context.mode.setFullScreen(true);
};
Der Aufruf an setFullScreen bewirkt, dass die Codekomponente den Vollbildmodus öffnet und die allocatedHeight
und allocatedWidth
entsprechend anpasst, weil trackContainerResize(true)
in der init
-Methode aufgerufen wurde. Sobald der Vollbildmodus geöffnet ist, wird updateView
aufgerufen und somit das Rendering der Komponente mit der neuen Größe aktualisiert. Die updatedProperties
enthält fullscreen_open
oder fullscreen_close
je nach Übergang, der gerade stattfindet.
Fügen Sie der CanvasGrid
-Klasse in index.ts
ein neues isFullScreen
-Feld hinzu, um den Zustand des Vollbildmodus zu speichern:
export class CanvasGrid implements ComponentFramework.StandardControl<IInputs, IOutputs> {
notifyOutputChanged: () => void;
container: HTMLDivElement;
context: ComponentFramework.Context<IInputs>;
sortedRecordsIds: string[] = [];
resources: ComponentFramework.Resources;
isTestHarness: boolean;
records: {
[id: string]: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord;
};
currentPage = 1;
filteredRecordCount?: number;
UpdateView bearbeiten, um den Status nachzuverfolgen
Fügen Sie Folgendes zur updateView
-Methode hinzu, um den Status nachzuverfolgen:
public updateView(context: ComponentFramework.Context<IInputs>): void {
const dataset = context.parameters.records;
const paging = context.parameters.records.paging;
const datasetChanged = context.updatedProperties.indexOf("dataset") > -1;
const resetPaging =
datasetChanged &&
!dataset.loading &&
!dataset.paging.hasPreviousPage &&
this.currentPage !== 1;
if (resetPaging) {
this.currentPage = 1;
}
Den Rückruf und das isFullScreen-Feld zum Rendern im Raster hinzufügen
Jetzt können Sie den Rückruf und das isFullScreen
-Feld in die Grid
-Rendering-Eigenschaften weitergeben:
ReactDOM.render(
React.createElement(Grid, {
width: allocatedWidth,
height: allocatedHeight,
columns: dataset.columns,
records: this.records,
sortedRecordIds: this.sortedRecordsIds,
hasNextPage: paging.hasNextPage,
hasPreviousPage: paging.hasPreviousPage,
currentPage: this.currentPage,
totalResultCount: paging.totalResultCount,
sorting: dataset.sorting,
filtering: dataset.filtering && dataset.filtering.getFilter(),
resources: this.resources,
itemsLoading: dataset.loading,
highlightValue: this.context.parameters.HighlightValue.raw,
highlightColor: this.context.parameters.HighlightColor.raw,
setSelectedRecords: this.setSelectedRecords,
onNavigate: this.onNavigate,
onSort: this.onSort,
onFilter: this.onFilter,
loadFirstPage: this.loadFirstPage,
loadNextPage: this.loadNextPage,
loadPreviousPage: this.loadPreviousPage,
}),
this.container
);
Zeilen hervorheben
Jetzt können Sie die Funktionalität zur bedingten Zeilenhervorhebung hinzufügen. Sie haben bereits die HighlightValue
- und HighlightColor
-Eingabeeigenschaften und den HighlightIndicator
property-set
festgelegt. Der property-set
ermöglicht es der die App erstellenden Person, ein Feld auszuwählen, das zum Vergleich mit dem von ihr in HighlightValue
bereitgestellten Wert verwendet wird.
Importtypen zur Unterstützung der Hervorhebung
Das benutzerdefinierte Zeilenrendering in DetailsList
erfordert einige zusätzliche Importe. Es gibt bereits einige @fluentui/react/lib/DetailsList
-Typen, fügen Sie also IDetailsListProps
, IDetailsRowStyles
und DetailsRow
zu der Importanweisung in Grid.tsx
hinzu.
import {
DetailsList,
ConstrainMode,
DetailsListLayoutMode,
IColumn,
IDetailsHeaderProps
} from '@fluentui/react/lib/DetailsList';
Jetzt erstellen Sie den benutzerdefinierten Zeilenrenderer, indem Sie Folgendes direkt unter dem const rootContainerStyle
-Block hinzu:
const onRenderRow: IDetailsListProps['onRenderRow'] = (props) => {
const customStyles: Partial<IDetailsRowStyles> = {};
if (props && props.item) {
const item = props.item as DataSet | undefined;
if (highlightColor && highlightValue && item?.getValue('HighlightIndicator') == highlightValue) {
customStyles.root = { backgroundColor: highlightColor };
}
return <DetailsRow {...props} styles={customStyles} />;
}
return null;
};
Sie sehen, dass:
- Sie können den Wert des Feldes, das von der die App erstellenden Person ausgewählt wurde, über das
HighlightIndicator
-Alias abrufen.
item?.getValue('HighlightIndicator')
. - Wenn der Wert des
HighlightIndicator
-Felds dem Wert vonhighlightValue
entspricht, den die Eingabeeigenschaft der Codekomponente bereitgestellt hat, können Sie der Zeile eine Hintergrundfarbe hinzufügen. - Die
DetailsRow
-Komponente wird von derDetailsList
verwendet, um die von Ihnen definierten Spalten zu rendern. Sie brauchen das Verhalten außer der Hintergrundfarbe nicht ändern.
Zusätzliche Eigenschaften zur Unterstützung der Hervorhebung hinzufügen
Fügen Sie einige zusätzliche Eigenschaften für highlightColor
und highlightValue
hinzu, die durch das Rendering in updateView
bereitgestellt werden. Sie haben sie bereits zur GridProps
-Schnittstelle hinzugefügt, also müssen Sie sie nur zur Destrukturierung der Eigenschaften hinzufügen:
export const Grid = React.memo((props: GridProps) => {
const {
records,
sortedRecordIds,
columns,
width,
height,
hasNextPage,
hasPreviousPage,
sorting,
filtering,
currentPage,
itemsLoading,
setSelectedRecords,
onNavigate,
onSort,
onFilter,
resources,
loadFirstPage,
loadNextPage,
loadPreviousPage,
onFullScreen,
isFullScreen,
} = props;
Die onRenderRow-Methode zur DetailsList hinzufügen
Geben Sie die onRenderRow
-Methode in die DetailsList
-Eigenschaften weiter:
<DetailsList
columns={gridColumns}
onRenderItemColumn={onRenderItemColumn}
onRenderDetailsHeader={onRenderDetailsHeader}
items={items}
setKey={`set${currentPage}`} // Ensures that the selection is reset when paging
initialFocusedIndex={0}
checkButtonAriaLabel="select row"
layoutMode={DetailsListLayoutMode.fixedColumns}
constrainMode={ConstrainMode.unconstrained}
selection={selection}
onItemInvoked={onNavigate}
></DetailsList>
Die Komponente bereitstellen und konfigurieren
Nachdem Sie alle Funktionen implementiert haben, müssen Sie die Codekomponente an Microsoft Dataverse zum Testen bereitstellen.
Stellen Sie in Ihrer Dataverse-Umgebung sicher, dass ein Herausgeber mit dem Präfix
samples
erstellt wurde:Dies könnte auch Ihr eigener Herausgeber sein, vorausgesetzt, Sie aktualisieren den Herausgeber-Präfix-Parameter im Aufruf von pac pcf push unten. Weitere Informationen: Erstellen eines Lösungsherausgebers.
Nachdem Sie den Herausgeber gespeichert haben, können Sie die CLI für Ihre Umgebung autorisieren, damit wir 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 eigenen Dataverse-Umgebung. Melden Sie sich mit Administrator-/Anpasserbenutzerdaten an, wenn Sie dazu aufgefordert werden. Die von diesen Benutzerrollen bereitgestellten Berechtigungen werden benötigt, um Codekomponenten für Dataverse bereitzustellen.Verwenden Sie zum Bereitstellen Ihrer Codekomponente:
pac pcf push --publisher-prefix samples
Hinweis
Wenn Sie den Fehler
Missing required tool: MSBuild.exe/dotnet.exe. Please add MSBuild.exe/dotnet.exe in Path environment variable or use 'Developer Command Prompt for VS
erhalten, müssen Sie entweder Visual Studio 2019 für Windows und Mac oder Build Tools für Visual Studio 2019 installieren und sicherstellen, dass Sie den Workload „.NET-Build Tools“ auswählen, wie in den Voraussetzungen beschrieben.Nach Abschluss dieses Vorgangs wird eine kleine temporäre Lösung namens PowerAppTools_samples in Ihrer Umgebung erstellt und die
CanvasGrid
Codekomponente wird dieser Lösung hinzugefügt. Sie können die Codekomponente bei Bedarf später in Ihre eigene Lösung verschieben. Weitere Informationen: Application Lifecycle Management (ALM) für Codekomponenten.Um Codekomponenten in Canvas-Apps zu verwenden, müssen Sie das Power Apps Component Framework für Canvas-Apps auf der Umgebung aktivieren, die Sie verwenden.
a. Öffnen Sie das Admin Center (admin.powerplatform.microsoft.com) und navigieren Sie zu Ihrer Umgebung. b. Gehen Sie zu Einstellungen > Produkt > Funktionen . Stellen Sie sicher, dass das Power Apps Component Framework für Canvas-Apps auf An gestellt ist:
Erstellen Sie eine neue Canvas-App mit dem Tablet-Layout.
Wählen Sie im Bereich Einfügen Weitere Komponenten abrufen aus.
Wählen Sie die Registerkarte Code im Bereich Komponenten importieren aus.
Wählen Sie die
CanvasGrid
-Komponente aus.Wählen Sie Importieren aus. Die Codekomponente erscheint nun unter Codekomponenten im Bereich Einfügen.
Ziehen Sie die
CanvasGrid
-Komponente auf den Bildschirm und binden Sie sie an dieContacts
-Tabelle in Microsoft Dataverse.Legen Sie die folgenden Eigenschaften auf der
CanvasGrid
Codekomponente mithilfe des Eigenschaftenbereichs fest:- Hervorhebungswert =
1
: Dies ist der Wert, denstatecode
hat, wenn der Datensatz inaktiv ist. - Hervorhebungsfarbe =
#FDE7E9
: Dies ist die Farbe, die verwendet wird, wenn der Datensatz inaktiv ist. HighlightIndicator
="statecode"
: Dies ist das Feld, mit dem verglichen werden soll. Dies ist im Bereich Erweitert im Abschnitt DATEN.
- Hervorhebungswert =
Fügen Sie eine neue
TextInput
-Komponente hinzu und nennen Sie sietxtSearch
.Aktualisieren Sie die
CanvasGrid.Items
-Eigenschaft aufSearch(Contacts,txtSearch.Text,"fullname")
.Sie werden feststellen, dass beim Eingeben der Texteingabe die Kontakte im Raster gefiltert werden.
Fügen sie eine neue Textbeschriftung hinzu und setzen Sie den Text auf „Keine Datensätze gefunden“. Positionieren Sie die Beschriftung oben auf dem Canvas-Raster.
Legen Sie die Eigenschaft Sichtbar der Textbeschriftung auf
CanvasGrid1.FilteredRecordCount=0
fest.
Dies bedeutet, dass die Beschriftung angezeigt wird, wenn keine Datensätze vorhanden sind, die dem txtSearch
-Wert entsprechen, oder wenn ein Spaltenfilter über das Kontextmenü angewendet wird, der keine Datensätze zurückgibt (z. B. Vollständiger Name enthält keine Daten).
Fügen Sie ein Anzeigeformular hinzu (aus der Gruppe Eingabe im Bereich Einfügen).
Legen Sie das Formular
DataSource
auf die TabelleContacts
fest und fügen Sie einige Formularfelder hinzu.Legen Sie die
Item
-Eigenschaft des Formulars aufCanvasGrid1.Selected
fest.Wenn Sie jetzt Elemente im Raster auswählen, sollten Sie sehen, dass das Formular die ausgewählten Elemente anzeigt.
Fügen Sie einen neuen Bildschirm zu der Canvas-App namens
scrDetails
hinzu.Kopieren Sie das Formular vom vorherigen Bildschirm und fügen Sie es in den neuen Bildschirm ein.
Legen Sie die
CanvasGrid1.OnSelect
-Eigenschaft aufNavigate(scrDetails)
fest.Sie sollten jetzt sehen, dass die App beim Aufrufen der Rasterzeilenauswahlaktion zum zweiten Bildschirm mit dem ausgewählten Element navigiert.
Debuggen nach der Bereitstellung
Sie können Ihre Codekomponente problemlos debuggen, während sie in der Canvas-App ausgeführt wird, indem Sie die Entwicklertools mit Ctrl+Shift+I
öffnen.
Wählen Sie Ctrl+P
und geben Sie Grid.tsx
oder Index.ts
ein. Sie können dann einen Haltepunkt setzen und Ihren Code schrittweise durchgehen.
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.
Der AutoResponder würde ungefähr so aussehen:
REGEX:(.*?)((?'folder'css|html)(%252f|\/))?SampleNamespace\.CanvasGrid[\.\/](?'fname'[^?]*\.*)(.*?)$
C:\repos\CanvasGrid\out\controls\CanvasGrid\${folder}\${fname}
Sie müssen auch die Filter aktivieren, um die Access-Control-Allow-Origin
-Kopfzeile hinzufügen. Mehr Informationen: Debuggen nach der Bereitstellung in Microsoft Dataverse.
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 einfach aktualisieren, da der Fiddler der Datei eine Cache-Steuerelementkopfzeile hinzufügt, um zu verhindern, dass sie zwischengespeichert wird.
Sobald Sie mit Ihren Änderungen zufrieden 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 CanvasGrid.pcfproj
verwenden. Fügen Sie unter dem OutputPath
Folgendes hinzu: <PcfBuildMode>production</PcfBuildMode>
<PropertyGroup>
<Name>CanvasGrid</Name>
<ProjectGuid>a670bba8-e0ae-49ed-8cd2-73917bace346</ProjectGuid>
<OutputPath>$(MSBuildThisFileDirectory)out\controls</OutputPath>
</PropertyGroup>
Ähnliche Artikel
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).