このチュートリアルでは、モデル駆動型アプリ field コンポーネントを作成し、Visual Studio Code を使用してフォーム上でコンポーネントをデプロイ、構成、テストします。 このコード コンポーネントでは、各選択肢の値の横にアイコンが表示された一連の選択肢がフォームに表示されます。 コンポーネントでは、選択肢の列定義 (メタデータ) や列レベルのセキュリティなど、モデル駆動型アプリの高度な機能の一部が使用されます。
これらの機能に加えて、コード コンポーネントがベスト プラクティスガイダンスに従っていることを確認します。
- 一貫性とアクセシビリティのためにMicrosoft Fluent UI を使用します。
- デザインと実行時の両方でのコード コンポーネント ラベルのローカライズ。
- 再利用性を向上するために、コード コンポーネントがメタデータ駆動型であることを保証します。
- フォーム ファクターと使用可能な幅に従ってコード コンポーネントがレンダリングされることを保証し、スペースが限られているアイコンを含むコンパクトなドロップダウンを表示します。
ChoicesPicker サンプル コードをダウンロードする
PowerApps-Samples/component-framework/ChoicesPickerControl/から完全なサンプルをダウンロードできます。
新しい pcfproj プロジェクトを作成する
注
開始する前に、 前提条件となるコンポーネントをすべてインストールしてください。
新しい pcfproj プロジェクトを作成するには:
コード コンポーネントを保持する新しいフォルダーを作成します。 たとえば、「
C:\repos\ChoicesPicker」のように入力します。Visual Studio Codeを開き、[ファイル]>[フォルダーを開く]に移動します。 前の手順で作成した
ChoicesPickerフォルダーを選択します。 Visual Studio Codeのインストール中に Windows Explorer 拡張機能を追加した場合は、フォルダー内の [コードで開く] コンテキスト メニュー オプションを使用することもできます。 現在のディレクトリがその場所に設定されているときにコマンド プロンプトで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
この手順では、必要なモジュールを定義するpackage.jsonなど、新しいChoicesPicker.pcfprojと関連ファイルを現在のフォルダーに追加します。 上記のコマンドでは、 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 をインストールする
Microsoft Fluent UI と React を使用して UI を作成するため、これらの依存関係をインストールします。 依存関係をインストールするには、次のコマンドを使用します。
npm install react react-dom @fluentui/react
このコマンドは、モジュールを packages.json ファイルに追加し、 node_modules フォルダーにインストールします。
npm installを使用して後で必要なすべてのモジュールを復元できるため、node_modulesをソース管理にコミットしないでください。
Microsoft Fluent UI の利点の 1 つは、一貫性があり、アクセシビリティの高い UI を提供することです。
eslint を構成する
pac pcf init によって使用されるテンプレートは、eslint モジュールをプロジェクトにインストールし、.eslintrc.json ファイルを追加して構成します。 TypeScript と React のコーディング スタイルの eslint を構成する必要があります。 詳細については、「 コード コンポーネントの ESLint の構成」を参照してください。
マニフェストを編集する
ChoicesPicker\ControlManifest.Input.xml ファイルは、コード コンポーネントの動作を記述するメタデータを定義します。
コントロール属性には、コンポーネントの名前空間と名前が既に含まれています。
次のバインドプロパティと入力プロパティを定義します。
| 名前 | Usage | タイプ | Description |
|---|---|---|---|
| 価値 | bound |
OptionSet | このプロパティを choice 列にリンクします。 コード コンポーネントは現在の値を受け取り、値が変更されたときに親コンテキストに通知します。 |
| アイコン マッピング | 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 メソッドは単一のルート コンポーネントをレンダリングする必要があります。
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を更新する
生成された index.ts ファイルを更新して、 ChoicesPickerComponentをレンダリングする必要があります。
コード コンポーネント内で React を使用すると、 updateView メソッドによってルート コンポーネントがレンダリングされます。 コンポーネントをコンポーネントにレンダリングするために必要なすべての値を渡します。 これらの値が変更されると、コンポーネントが再レンダリングされます。
import ステートメントを追加してアイコンを初期化する
index.ts ファイルでChoicesPickerComponent コンポーネントを使用する前に、ファイルの先頭に次のコードを追加します。
-
の前に
-
後の
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 メソッドを追加する
ユーザーが選択した値を変更したら、onChange イベントからnotifyOutputChangedを呼び出します。
関数を追加します。
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 の戻りノードの編集
ChoicesPickerComponent内で React ノードを返すときは、これらの新しい入力プロパティを使用して、ピッカーが無効またはマスクされていることを確認します。
-
の前に
-
後の
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}
/>
)}
</>
);
formFactorが大きい場合はChoiceGroupコンポーネントを出力し、小さい場合は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 prop に基づいてレンダリングが異なったので、 index.ts内のレンダー呼び出しから正しい値を渡します。
SmallFormFactorMaxWidth 列挙型と FormFactors 列挙型を追加する
index.ts内の export class ChoicesPicker クラスの直前に次のコードを追加します。
const SmallFormFactorMaxWidth = 350;
const enum FormFactors {
Unknown = 0,
Desktop = 1,
Tablet = 2,
Phone = 3,
}
SmallFormFactorMaxWidthはコンポーネントがDropdownではなくChoiceGroupを使用してレンダリングを開始するときの幅です。
FormFactors列挙型は、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 push の呼び出しでパブリッシャー プレフィックス パラメーターを適宜更新する必要があります。
詳細については、「 ソリューション発行元の作成」を参照してください。
パブリッシャーを保存した後、コンパイル済みのコード コンポーネントをプッシュできるように、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 ファイルを編集した後、pac pcf プッシュを使用して最適化されたビルドをデプロイすることを選択できます。
OutputPathの下に、次のコードを追加します。
<PcfBuildMode>production</PcfBuildMode>
関連資料
Microsoft Power Platform によるアプリケーション ライフサイクル管理 (ALM)
Power Apps コンポーネント フレームワーク API リファレンス
最初のコンポーネントを作成する
コード コンポーネントのデバッグ