このチュートリアルでは、モデル駆動型アプリ field コンポーネントを作成し、Visual Studio Code を使用してフォーム上でコンポーネントをデプロイ、構成、テストします。 このコード コンポーネントでは、各選択肢の値の横にアイコンが表示された一連の選択肢がフォームに表示されます。 コンポーネントでは、選択肢の列定義 (メタデータ) や列レベルのセキュリティなど、モデル駆動型アプリの高度な機能の一部が使用されます。
これらに加えて、コード コンポーネントがベスト プラクティス ガイダンスに従っていることを確認します。
- 一貫性とアクセシビリティのための Microsoft Fluent UI の使用
- デザインと実行時の両方でのコード コンポーネント ラベルのローカライズ
- 再利用性を向上するために、コード コンポーネントがメタデータ駆動型であることを保証する
- フォーム ファクターと使用可能な幅に従ってコード コンポーネントがレンダリングされることを保証し、スペースが限られているアイコンを含むコンパクトなドロップダウンを表示します
Code
PowerApps-Samples/component-framework/ChoicesPickerControl/から完全なサンプルをダウンロードできます。
新しい pcfproj プロジェクトを作成する
注
開始する前に、 前提条件となるコンポーネントがすべてインストールされていることを確認してください。
新しい pcfprojを作成するには:
コード コンポーネントを保持する新しいフォルダーを作成します。 たとえば、「
C:\repos\ChoicesPicker」のように入力します。Visual Studio Code を開き、[ ファイル>フォルダーを開く ] に移動し、前の手順で作成した
ChoicesPickerフォルダーを選択します。 Visual Studio Code のインストール中に Windows エクスプローラー拡張機能を追加した場合は、フォルダー内の [ コードで開く ] コンテキスト メニュー オプションを使用することもできます。 現在のディレクトリがその場所に設定されている場合は、コマンド プロンプトでcode .を使用して、Visual Studio Code に任意のフォルダーを追加することもできます。新しい Visual Studio Code PowerShell ターミナル (ターミナル>New ターミナル) 内 で、pac pcf init コマンドを使用して新しいコード コンポーネント プロジェクトを作成します。
pac pcf init ` --namespace SampleNamespace ` --name ChoicesPicker ` --template field ` --run-npm-installまたは短い形式を使用します。
pac pcf init -ns SampleNamespace -n ChoicesPicker -t field -npm
これにより、新しい ChoicesPicker.pcfproj と関連ファイルが現在のフォルダーに追加されます。これには、必要なモジュールを定義する package.json が含まれます。 上記のコマンド npm install コマンドを実行して、必要なモジュールをインストールします。
Running 'npm install' for you...
注
エラー The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program.が発生した場合は、 node.js (LTS バージョンをお勧めします) とその他のすべての前提条件がインストールされていることを確認してください。
テンプレートには、さまざまな構成ファイルと共に index.ts ファイルが含まれていることがわかります。 これはコード コンポーネントの開始点であり、「コンポーネントの 実装」で説明されているライフサイクル メソッドが含まれています。
Microsoft Fluent UI をインストールする
UI の作成には Microsoft Fluent UI と React を使用するため、これらを依存関係としてインストールする必要があります。 依存関係をインストールするには、次のコマンドを使用します。
npm install react react-dom @fluentui/react
これにより、モジュールが packages.json に追加され、 node_modules フォルダーにインストールされます。 必要なすべてのモジュールは後で node_modules を使用して復元されるため、ソース管理にnpm installをコミットしません。
Microsoft Fluent UI の利点の 1 つは、一貫性があり 、アクセシビリティ の高い UI を提供することです。
設定する eslint
pac pcf init によって使用されるテンプレートは、eslint モジュールをプロジェクトにインストールし、.eslintrc.json ファイルを追加して構成します。
Eslint では、TypeScript と React のコーディング スタイルを構成する必要があります。 詳細情報: Linting - コード コンポーネントのベスト プラクティスとガイダンス。
マニフェストを編集する
ChoicesPicker\ControlManifest.Input.xml ファイルは、コード コンポーネントの動作を記述するメタデータを定義します。
コントロール属性には、コンポーネントの名前空間と名前が既に含まれています。
次のバインドプロパティと入力プロパティを定義する必要があります。
| 名前 | Usage | タイプ | Description |
|---|---|---|---|
| 価値 | bound |
OptionSet | このプロパティは、選択肢の列にリンクされます。 コード コンポーネントは現在の値を受け取り、値が変更されたときに親コンテキストに通知します。 |
| アイコン マッピング | input |
複数行のテキスト | アプリ 作成者がコード コンポーネントをフォームに追加すると、このプロパティの値が設定されます。 これには、選択値ごとに使用できるアイコンを構成するための JSON 文字列が含まれています。 |
詳細情報: プロパティ要素。
ヒント
XML は、属性が別々の行に表示されるように書式設定することで、読みやすくなる場合があります。 Visual Studio Code Marketplace で、選択した XML 書式設定ツールを検索してインストールします。 XML 書式設定拡張機能を検索します。
次の例は、読みやすくするために、別々の行に属性を使用して書式設定されています。
既存の sampleProperty を新しいプロパティに置き換える
ChoicesPicker\ControlManifest.Input.xmlを開き、コントロール要素内に次のプロパティ定義を貼り付け、既存のsamplePropertyを置き換えます。
-
の前に
-
後の
<property name="sampleProperty"
display-name-key="Property_Display_Key"
description-key="Property_Desc_Key"
of-type="SingleLine.Text"
usage="bound"
required="true" />
変更を保存し、次のコマンドを使用してコンポーネントをビルドします。
npm run build
コンポーネントがビルドされると、次のことがわかります。
自動的に生成されたファイル
ChoicesPicker\generated\ManifestTypes.d.tsがプロジェクトに追加されます。 これは、ControlManifest.Input.xmlからビルド プロセスの一部として生成され、入力/出力プロパティを操作するための型を提供します。ビルド出力が
outフォルダーに追加されます。bundle.jsは、ブラウザー内で実行されるトランスパイルされた JavaScript です。ControlManifest.xmlは、デプロイ時に使用されるControlManifest.Input.xmlファイルの再フォーマットされたバージョンです。注
generatedフォルダーとoutフォルダーの内容を直接変更しないでください。 ビルド プロセスの一部として上書きされます。
ChoicesPicker Fluent UI React コンポーネントを実装する
コード コンポーネントで React を使用する場合は、 updateView メソッド内にレンダリングされる 1 つのルート コンポーネントが必要です。
ChoicesPicker フォルダー内に、ChoicesPickerComponent.tsxという名前の新しい TypeScript ファイルを追加し、次の内容を追加します。
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';
注
ファイルには拡張子 tsxがあります。これは、React で使用される XML スタイル構文をサポートする TypeScript ファイルです。 ビルド プロセスによって標準の JavaScript にコンパイルされます。
ChoicesPickerComponent デザイン ノート
このセクションには、 ChoicesPickerComponentの設計に関するコメントが含まれています。
機能コンポーネントです
これは React 関数コンポーネントですが、 クラス コンポーネントである場合もあります。 これは、好みのコーディング スタイルに基づいています。 クラス コンポーネントと機能コンポーネントは、同じプロジェクトで混在させることもできます。 関数コンポーネントとクラス コンポーネントの両方で、React で使用される tsx XML スタイル構文が使用されます。 詳細情報: 関数コンポーネントとクラス コンポーネント
bundle.js サイズを最小限に抑える
「パスベースのインポートを使用して ChoiceGroup Fluent UI コンポーネントをインポートする場合は、次の方法ではなく、これを使用します。」
import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react';
次の情報を使用します。
import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';
これにより、バンドル サイズが小さくなり、容量要件が低くなり、実行時のパフォーマンスが向上します。
別の方法として、ツリーシェーキングを使用します。
'props' の説明
入力プロパティには、index.ts メソッドでupdateViewによって提供される次の属性があります。
prop |
Description |
|---|---|
label |
コンポーネントにラベルを付けるために使用します。 これは、モデル駆動型アプリ内で選択された UI 言語を使用して、親コンテキストによって提供されるメタデータ フィールド ラベルにバインドされます。 |
value |
マニフェストで定義されている入力プロパティにリンクされています。 レコードが新しい場合、またはフィールドが設定されていない場合は、null を指定できます。 TypeScript null は、プロパティ値を渡す/返すときに undefined ではなく使用されます。 |
options |
コード コンポーネントがモデル駆動型アプリの選択肢列にバインドされている場合、プロパティには使用可能な選択肢を記述する OptionMetadata が含まれます。 これをコンポーネントに渡して、各項目をレンダリングできるようにします。 |
configuration |
コンポーネントの目的は、使用可能な各選択肢のアイコンを表示するためです。 構成は、コード コンポーネントをフォームに追加するときに、アプリ 作成者によって提供されます。 このプロパティは、各数値選択値を Fluent UI アイコン名にマップする JSON 文字列を受け入れます。 たとえば、「 {"0":"ContactInfo","1":"Send","2":"Phone"} 」のように入力します。 |
onChange |
ユーザーが選択肢の選択を変更すると、React コンポーネントによって onChange イベントがトリガーされます。 その後、コード コンポーネントは notifyOutputChanged を呼び出して、モデル駆動型アプリが新しい値で列を更新できるようにします。 |
制御された React コンポーネント
React コンポーネントには、次の 2 種類があります。
| タイプ | Description |
|---|---|
| 制御されていない | 内部状態を維持し、入力プロパティを既定値としてのみ使用します。 |
| 制御 | コンポーネントのプロパティによって渡された値をレンダリングします。
onChange イベントが prop 値を更新しない場合、ユーザーは UI に変更を表示しません。 |
ChoicesPickerComponentは制御されたコンポーネントであるため、モデル駆動型アプリが (notifyOutputChanged呼び出しの後に) 値を更新すると、新しい値でupdateViewが呼び出され、コンポーネントのプロパティに渡され、更新された値が表示される再レンダリングが発生します。
destructuring の割り当て
props定数の割り当て: const { label, value, options, onChange, configuration } = props;では分割代入が使用されます。 この方法では、使用するたびに props を前に付けるのではなく、プロパティからレンダリングに必要な属性を抽出します。
React コンポーネントとフックの使用
次に、 ChoicesPickerComponent.tsx で React コンポーネントとフックを使用する方法について説明します。
| Item | Explanation |
|---|---|
| React.memo | いずれかの入力プロパティが変更されない限りレンダリングされないように、関数コンポーネントをラップします。 |
| React.useMemo | 作成された項目配列が変更されるのは、入力プロパティ options または configuration が変更された場合のみです。 これは、子コンポーネントの不要なレンダリングを減らす機能コンポーネントのベスト プラクティスです。 |
| React.useCallback | Fluent UI ChoiceGroup 値が変更されたときに呼び出されるコールバック クロージャを作成します。 この React フックにより、入力プロパティの onChange が変更されたときにのみコールバック クロージャが変更されます。 これは、 useMemoに似たパフォーマンスのベスト プラクティスです。 |
構成入力プロパティのエラー動作
JSON 構成入力プロパティの解析に失敗した場合、エラーは items.errorを使用してレンダリングされます。
ChoicesPicker コンポーネントをレンダリングするようにindex.tsを更新する
ChoicesPickerComponent をレンダリングするには、生成された index.ts file を更新する必要があります。
コード コンポーネント内で React を使用する場合、ルート コンポーネントのレンダリングは updateView メソッド内で実行されます。 コンポーネントをレンダリングするために必要なすべての値は、コンポーネントが変更されたときに再レンダリングされるようにコンポーネントに渡されます。
import ステートメントを追加してアイコンを初期化する
ChoicesPickerComponentでindex.tsを使用するには、ファイルの先頭に次のコードを追加する必要があります。
-
の前に
-
後の
import { IInputs, IOutputs } from "./generated/ManifestTypes";
注
Fluent UI アイコン セットを使用しているため、 initializeIcons のインポートが必要です。 テスト ハーネス内にアイコンを読み込むには、 initializeIcons を呼び出す必要があります。 モデル駆動型アプリ内では、既に初期化されています。
ChoicesPicker クラスに属性を追加する
コード コンポーネントは、属性を使用してインスタンスの状態を維持します。 (これは React コンポーネントの状態とは異なります)。
index.ts
ChoicesPicker クラス内に、次の属性を追加します。
-
の前に
-
後の
export class ChoicesPicker implements ComponentFramework.StandardControl<IInputs, IOutputs> {
次の表に、これらの属性について説明します。
| 特性 | Description |
|---|---|
notifyOutputChanged |
ユーザーが選択値を変更し、コード コンポーネントが親コンテキストに戻す準備ができていることをモデル駆動型アプリに通知するために使用されるメソッドへの参照を保持します。 |
rootContainer |
モデル駆動型アプリ内のコード コンポーネントを保持するために作成された HTML DOM 要素。 |
selectedValue |
getOutputs メソッド内で返すことができるように、ユーザーが選択した選択の状態を保持します。 |
context |
マニフェストで定義されているプロパティとその他のランタイム プロパティを読み取り、 trackContainerResizeなどの API メソッドにアクセスするために使用される Power Apps コンポーネント フレームワーク コンテキスト。 |
init メソッドを更新する
これらの属性を設定するには、 init メソッドを更新します。
-
の前に
-
後の
public init(
context: ComponentFramework.Context<IInputs>,
notifyOutputChanged: () => void,
state: ComponentFramework.Dictionary,
container: HTMLDivElement):
void {
// Add control initialization code
}
init メソッドは、アプリ画面でコード コンポーネントが初期化されるときに呼び出されます。
onChange メソッドを追加する
ユーザーが選択した値を変更したら、notifyOutputChanged イベントからonChangeを呼び出す必要があります。
関数を追加します。
onChange = (newValue: number | undefined): void => {
this.selectedValue = newValue;
this.notifyOutputChanged();
};
getOutputs メソッドを更新する
-
の前に
-
後の
public getOutputs(): IOutputs {
return {};
}
ヒント
モデル駆動型アプリで以前にクライアント API スクリプトを記述したことがある場合は、フォーム コンテキストを使用して属性値を更新するために使用できます。 コード コンポーネントは、このコンテキストにアクセスしないでください。 代わりに、 notifyOutputChanged と getOutputs に依存して、1 つ以上の変更された値を指定します。
IOutput インターフェイスで定義されているすべてのバインドされたプロパティを返す必要はありません。値を変更したプロパティのみ。
updateView メソッドを更新する
次に、 updateView を更新して ChoicesPickerComponentをレンダリングします。
-
の前に
-
後の
public updateView(context: ComponentFramework.Context<IInputs>): void {
// Add code to update control view
}
context.parameters.valueからラベルとオプションをプルしていることに注意してください。value.rawでは、選択した数値の選択肢が表示され、値が選択されていない場合はnullされます。
destroy 関数を編集する
最後に、コード コンポーネントが破棄されたときに整理する必要があります。
-
の前に
-
後の
public destroy(): void {
// Add code to cleanup control if necessary
}
詳細情報: ReactDOM.unmountComponentAtNode
テスト ハーネスを起動する
すべてのファイルが保存されていることを確認し、ターミナルで次のコマンドを使用してください。
npm start watch
テスト ハーネスは、新しいブラウザー ウィンドウ内にレンダリングされた選択肢ピッカーから始まることがわかります。 最初は、文字列プロパティ configuration の既定値が valされているため、エラーが表示されます。 テスト ハーネスの既定の選択肢 0、1、2 を次の Fluent UI アイコンでマップするように構成を設定します。
{"0":"ContactInfo","1":"Send","2":"Phone"}
選択したオプションを変更すると、右側の [ データ入力] パネルに値が表示されます。 さらに、値を変更すると、コンポーネントには、更新された関連する値が表示されます。
読み取り専用および列レベルのセキュリティのサポート
モデル駆動型アプリのコンポーネントfieldを作成する際には、アプリケーションが、列レベルのセキュリティのために読み取り専用またはマスクされた場合の制御状態を尊重する必要があります。 列が読み取り専用の場合にコード コンポーネントが読み取り専用 UI をレンダリングしないとき、状況によっては(たとえば、レコードが非アクティブな場合に)本来は更新できない列についてユーザーに更新が可能になってしまうことがあります。 詳細情報: アクセスを制御するための列レベルのセキュリティ。
読み取り専用および列レベルのセキュリティのために updateView メソッドを編集する
index.tsで、updateView メソッドを編集して、disabledフラグとmasked フラグを取得する次のコードを追加します。
-
の前に
-
後の
public updateView(context: ComponentFramework.Context<IInputs>): void {
const { value, configuration } = context.parameters;
if (value && value.attributes && configuration) {
ReactDOM.render(
React.createElement(ChoicesPickerComponent, {
label: value.attributes.DisplayName,
options: value.attributes.Options,
configuration: configuration.raw,
value: value.raw,
onChange: this.onChange,
}),
this.rootContainer,
);
}
}
列レベルのセキュリティ構成がバインドされた列に適用されている場合、 value.security はモデル駆動型アプリ内でのみ設定されます。
これらの値は、そのプロパティを介して React コンポーネントに渡すことができます。
ChoicesPickerComponent を編集して、無効なプロパティとマスクされたプロパティを追加する
ChoicesPickerComponent.tsxでは、disabled インターフェイスにプロパティを追加することで、maskedプロパティとChoicesPickerComponentProps プロパティを受け入れることもできます。
-
の前に
-
後の
export interface ChoicesPickerComponentProps {
label: string;
value: number | null;
options: ComponentFramework.PropertyHelper.OptionMetadata[];
configuration: string | null;
onChange: (newValue: number | undefined) => void;
}
ChoicesPickerComponent プロパティの編集
新しい属性を props に追加します。
-
の前に
-
後の
export const ChoicesPickerComponent = React.memo((props: ChoicesPickerComponentProps) => {
const { label, value, options, configuration, onChange } = props;
ChoicesPickerComponent の戻りノードの編集
React ノードを返すときの ChoicesPickerComponent 内では、これらの新しい入力プロパティを使用して、ピッカーが無効またはマスクされていることを確認できます。
-
の前に
-
後の
return (
<>
{items.error}
<ChoiceGroup
label={label}
options={items.choices}
selectedKey={valueKey}
onChange={onChangeChoiceGroup}
/>
</>
);
注
読み取り専用フィールドや列レベル セキュリティをシミュレートできないため、テスト ハーネスに違いは見られません。 これは、モデル駆動型アプリケーション内にコントロールをデプロイした後でテストする必要があります。
コード コンポーネントの応答性を高めます
コード コンポーネントは、Web、タブレット、モバイル アプリでレンダリングできます。 使用可能な領域を考慮することが重要です。 使用可能な幅が制限されている場合は、選択肢コンポーネントをドロップダウンとしてレンダリングします。
ドロップダウン コンポーネントとアイコンをインポートする
ChoicesPickerComponent.tsxでは、コンポーネントは Fluent UI Dropdown コンポーネントを使用して小さなバージョンをレンダリングするため、インポートに追加します。
-
の前に
-
後の
import { ChoiceGroup, IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';
import * as React from 'react';
formFactor prop を追加する
新しい prop formFactorに応じて異なる方法でレンダリングされるようにコード コンポーネントを更新します。
ChoicesPickerComponentProps インターフェイスに次の属性を追加します。
-
の前に
-
後の
export interface ChoicesPickerComponentProps {
label: string;
value: number | null;
options: ComponentFramework.PropertyHelper.OptionMetadata[];
configuration: string | null;
onChange: (newValue: number | undefined) => void;
disabled: boolean;
masked: boolean;
}
ChoicesPickerComponent プロパティに formFactor を追加する
プロパティに formFactor を追加します。
-
の前に
-
後の
export const ChoicesPickerComponent = React.memo((props: ChoicesPickerComponentProps) => {
const { label, value, options, configuration, onChange, disabled, masked } = props;
メソッドを追加し、ドロップダウン コンポーネントをサポートするように変更する
ドロップダウン コンポーネントには、いくつかの異なるレンダリング方法が必要です。
ChoicesPickerComponentの上に、次のコードを追加します。const iconStyles = { marginRight: '8px' }; const onRenderOption = (option?: IDropdownOption): JSX.Element => { if (option) { return ( <div> {option.data && option.data.icon && ( <Icon style={iconStyles} iconName={option.data.icon} aria-hidden="true" title={option.data.icon} /> )} <span>{option.text}</span> </div> ); } return <></>; }; const onRenderTitle = (options?: IDropdownOption[]): JSX.Element => { if (options) { return onRenderOption(options[0]); } return <></>; };これらのメソッドは、ドロップダウン値の横に正しいアイコンをレンダリングするために、
Dropdownによって使用されます。新しい
onChangeDropDownメソッドを追加します。onChangeメソッドがDropdownのために必要です。これはChoiceGroupイベント ハンドラーと同様です。 既存のonChangeChoiceGroupのすぐ下に、新しいDropdownバージョンを追加します。const onChangeDropDown = React.useCallback( (ev: unknown, option?: IDropdownOption): void => { onChange(option ? (option.data.value as number) : undefined); }, [onChange], );
表示される出力を変更する
新しい formFactor プロパティを使用するには、次の変更を行います。
-
の前に
-
後の
return (
<>
{items.error}
{masked && '****'}
{!items.error && !masked && (
<ChoiceGroup
label={label}
options={items.choices}
selectedKey={valueKey}
disabled={disabled}
onChange={onChangeChoiceGroup}
/>
)}
</>
);
ChoiceGroupが大きい場合はformFactorコンポーネントを出力し、小さい場合はDropdownを使用していることがわかります。
ドロップダウンオプションを返します (Return DropdownOptions)
ChoicesPickerComponent.tsxで最後に行う必要があるのは、オプションメタデータをChoicesGroupで使用されているものと少し異なる方法でマップすることです。そのため、既存のitemsの下にあるchoices戻りブロック内で、options.map、次を追加します。
-
の前に
-
後の
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の編集
選択肢コンポーネントが formFactor プロパティに基づいてレンダリングが異なるようになったので、 index.ts内のレンダー呼び出しから正しい値を渡す必要があります。
SmallFormFactorMaxWidth 列挙型と FormFactors 列挙型を追加する
export class ChoicesPicker内の index.ts クラスのすぐ上に次を追加します。
const SmallFormFactorMaxWidth = 350;
const enum FormFactors {
Unknown = 0,
Desktop = 1,
Tablet = 2,
Phone = 3,
}
SmallFormFactorMaxWidthはコンポーネントがChoiceGroupではなくDropdownを使用してレンダリングを開始するときの幅です。
FormFactors
enumは、context.client.getFormFactorを呼び出すときに便利に使用されます。
formFactor を検出するコードを追加する
既存の小道具の下にある React.createElement の小道具に次のコードを追加します。
-
の前に
-
後の
React.createElement(ChoicesPickerComponent, {
label: value.attributes.DisplayName,
options: value.attributes.Options,
configuration: configuration.raw,
value: value.raw,
onChange: this.onChange,
disabled: disabled,
masked: masked,
}),
サイズ変更の更新を要求する
context.mode.allocatedWidthを使用しているため、使用可能な幅が変更されたときに (updateViewの呼び出しを介して) 更新プログラムを受信することをモデル駆動型アプリに通知する必要があります。
initへの呼び出しを追加することで、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;
}
テスト ハーネスを試す
今、すべての変更を保存すれば、テストハーネスブラウザーウィンドウに自動的に反映されます(npm start watch がすでに実行されているため)。
コンポーネント コンテナーの幅の値を 349 から 350 に切り替え、レンダリングの動作が異なることがわかります。
Web と Phone の間でフォーム ファクターを入れ替えて、同じ動作を確認することもできます。
ローカライゼーション
複数の言語をサポートする場合、コード コンポーネントは、デザイン文字列とランタイム文字列の両方に翻訳を提供するリソース ファイルを保持できます。
ChoicesPicker\strings\ChoicesPicker.1033.resx場所に新しいファイルを追加します。 別のロケールのラベルを追加する場合は、1033 (en-us) を選択したロケールに変更します。Visual Studio Code リソース エディターを使用して、次のように入力します。
名前 価値 ChoicesPicker_Name選択肢の選択 (モデル駆動型) ChoicesPicker_Desc選択内容をアイコン付きのピッカーとして表示する Value_Name価値 Value_Descコントロールに関連付ける選択項目フィールド Configuration_Nameアイコン マッピングの構成 Configuration_Desc選択値を fluent ui アイコンにマップする構成。 例: {"1":"ContactInfo","2":"Send"} それ以外の場合は、.resx ファイルの内容を次の XML で設定します。
<?xml version="1.0" encoding="utf-8"?> <root> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> <xsd:element name="root" msdata:IsDataSet="true"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="metadata"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0"/> </xsd:sequence> <xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute ref="xml:space"/> </xsd:complexType> </xsd:element> <xsd:element name="assembly"> <xsd:complexType> <xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string"/> </xsd:complexType> </xsd:element> <xsd:element name="data"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute ref="xml:space"/> </xsd:complexType> </xsd:element> <xsd:element name="resheader"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:schema> <resheader name="resmimetype"> <value>text/microsoft-resx</value> </resheader> <resheader name="version"> <value>2.0</value> </resheader> <resheader name="reader"> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <data name="ChoicesPicker_Name" xml:space="preserve"> <value>Choices Picker (Model Driven)</value> <comment/> </data> <data name="ChoicesPicker_Desc" xml:space="preserve"> <value>Shows choices as a picker with icons</value> <comment/> </data> <data name="Value_Name" xml:space="preserve"> <value>Value</value> <comment/> </data> <data name="Value_Desc" xml:space="preserve"> <value>The choices field to bind the control to</value> <comment/> </data> <data name="Configuration_Name" xml:space="preserve"> <value>Icon Mapping Configuration</value> <comment/> </data> <data name="Configuration_Desc" xml:space="preserve"> <value>Configuration that maps the choice value to a fluent ui icon. E.g. {"1":"ContactInfo","2":"Send"}</value> <comment/> </data> </root>ヒント
resxファイルを直接編集することはお勧めしません。 Visual Studio Code リソース エディターまたは Visual Studio Code の拡張機能を使用すると、この作業が簡単になります。
リソース文字列のマニフェストを更新する
リソース文字列が作成されたので、次のように ControlManifest.Input.xml を更新することで、それらを参照できます。
-
の前に
-
後の
<?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>
次のことがわかります。
-
display-name-keyとdescription-keyの値は、resxファイル内の対応するキーを指すようになりました。 -
resources要素には、コード コンポーネントが参照先ファイルからリソースを読み込む必要があることを示す追加のエントリがあります。
コンポーネントで使用するために追加の文字列が必要な場合は、それらを resx に追加し、 getString を使用して実行時に文字列を読み込むことができます。 詳細情報: ローカライズ API コンポーネントの実装。
注
テスト ハーネスの制限の 1 つは、リソース ファイルを読み込まないという点です。そのため、コンポーネントを Microsoft Dataverse にデプロイして、コンポーネントを完全にテストする必要があります。
モデル駆動型アプリでのデプロイと構成
テスト ハーネスで基本的な機能をテストしたら、モデル駆動型アプリ内でコード コンポーネントをエンド ツー エンドで完全にテストできるように、コンポーネントを Microsoft Dataverse にデプロイする必要があります。
Dataverse 環境内で、
samplesのプレフィックスを持つパブリッシャーが作成されていることを確認します。
同様に、以下の pac pcf プッシュ の呼び出しでパブリッシャー プレフィックス パラメーターを更新する場合は、これがパブリッシャーである可能性があります。 詳細: ソリューション発行元を作成する。
発行元を保存したら、コンパイル済みのコード コンポーネントをプッシュできるように、環境に対して Microsoft Power Platform CLI を承認する準備が整います。 コマンド ラインで、次のコマンドを使用します。
pac auth create --url https://myorg.crm.dynamics.commyorg.crm.dynamics.comを Dataverse 環境の URL に置き換えます。 メッセージが表示されたら、システム管理者またはカスタマイザー特権でサインインします。 Dataverse にコード コンポーネントをデプロイするには、これらのロールによって提供される特権が必要です。コード コンポーネントをデプロイするには、次を使用します。
pac pcf push --publisher-prefix samples注
エラー
Missing required tool: MSBuild.exe/dotnet.exeが発生した場合は、Path 環境変数にMSBuild.exe/dotnet.exeを追加するか、Developer Command Prompt for Visual Studio Codeを使用します。 Visual Studio 2019 for Windows & Mac または Build Tools for Visual Studio 2019 をインストールする必要があります。 前提条件の説明に従って、.NET build toolsワークロードを選択してください。このプロセスが完了すると、環境内に PowerAppTools_samples という名前の一時的なソリューションが作成されます。
ChoicesPickerコード コンポーネントがこのソリューションに追加されます。 必要に応じて、後でコード コンポーネントをソリューションに移動できます。 詳細情報: コード コンポーネント アプリケーション ライフサイクル管理 (ALM)。
次に、クラシック エディターでメイン フォームに移動し、連絡先フォームにコードコンポーネントを追加します。[優先する連絡方法]を選択し、[プロパティの変更], [コントロール タブ]で [コントロールの追加] を選び、 [選択ピッカー] を選択してから、追加をクリックします。
注
将来的には、モデル駆動型アプリ フォームでコード コンポーネントを構成するためにクラシック エディターは必要ありません。
コンポーネントに次のプロパティを設定します。
Web、電話、タブレットの既定値として選択ピッカーを設定します。
編集アイコンを選択し、[静的な値にバインド] を選択して、アイコン マッピング構成に次の文字列を入力します。
{ "1":"ContactInfo", "2":"Send", "3":"Phone", "4":"Fax", "5":"DeliveryTruck" }これらは、各選択肢の値に使用される Fluent UI アイコンです。
選択ピッカーの上にラベルが表示されるので、[表示] タブを選択し、フォームの [ラベルの表示] チェック ボックスをオフにします。
フォームを保存して発行します。
正しいフォームが選択された状態で、モデル駆動型アプリ内で連絡先レコードを開きます。 標準のドロップダウン コントロールではなく、
ChoicesPickerコード コンポーネントが表示されます。 (コンポーネントを表示するには、ページのハード リロードが必要になる場合があります)。注
テスト ハーネスでは、モデル駆動型アプリと比較してテキストの配置が若干異なる場合があります。 これは、テスト ハーネスには、モデル駆動型アプリの CSS ルールが異なるためです。 このため、デプロイ後は常にコード コンポーネントを完全にテストすることをお勧めします。
Dataverse へのデプロイ後のデバッグ
コンポーネントをさらに変更する必要がある場合は、毎回デプロイする必要はありません。 代わりに、「 コード コンポーネントのデバッグ 」で説明されている手法を使用して Fiddler AutoResponder を 作成し、 npm start watch の実行中にローカル ファイル システムからファイルを読み込みます。
注
テスト ハーネスを使用してすべての機能をテストできる場合は、Dataverse へのデプロイ後にデバッグする必要がない場合があります。 ただし、コード コンポーネントを配布する前に、常に Dataverse 内にデプロイしてテストすることをお勧めします。
AutoResponder は次のようになります。
REGEX:(.*?)((?'folder'css|html)(%252f|\/))?SampleNamespace\.ChoicesPicker[\.\/](?'fname'[^?]*\.*)(.*?)$
C:\repos\ChoicesPicker\out\controls\ChoicesPicker\${folder}\${fname}
AutoResponder ファイルを取得するには、ブラウザー セッションでキャッシュを空にし、ハード更新する必要があります。 読み込まれたら、Fiddler がキャッシュ制御ヘッダーをファイルに追加してキャッシュされないようにするため、ブラウザーを更新できます。
変更が完了したら、マニフェストのパッチ バージョンをインクリメントし、 pac pcf プッシュを使用して再デプロイできます。
ここまでは、最適化されておらず、実行時に実行速度が遅くなる開発ビルドをデプロイしました。
を編集して、ChoicesPicker.pcfprojを使用して最適化されたビルドをデプロイすることを選択できます。
OutputPathの下に、次のコードを追加します。
<PcfBuildMode>production</PcfBuildMode>
関連資料
Microsoft Power Platform によるアプリケーション ライフサイクル管理 (ALM)
Power Apps コンポーネント フレームワーク API リファレンス
最初のコンポーネントを作成する
コード コンポーネントのデバッグ