PowerAppsで、遷移先のスクリーンをドロップダウンで選択する

## 概要
PowerAppsで、Navigate関数でスクリーンを遷移する際、Dropdownコントロールで選択したスクリーンに遷移する方法です。
Dropdownコントロールのソースに、Screenコントロールをぶち込んで、

## 準備
こんな感じで、メインスクリーンのほか、遷移先となるスクリーンを３つほど作成します。（もっとたくさん作っても構いません）
![2022-08-11_08h56_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/0bf99718-9d74-d0a4-4868-c650f82db69e.png)
### メインスクリーン
メインスクリーンは、遷移先を選択するDropdownと、Navigate関数を実行するButtonコントロールを配置。
![2022-08-11_08h57_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/cbc96f66-216e-e25d-6166-116389cc9ad3.png)
### 画面A・B・C
画面Aには、画面Aであることが分かるようにするLabelと、戻るアイコンを配置。
戻るアイコンには、OnSelectに、Back()関数を記述
![2022-08-11_08h58_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/013586e8-4a22-2a52-948d-dc86de94e6d6.png)
画面Bと画面Cも同様。

## 失敗
ここから、ロジックを記述していきます。
### App の OnStart
OnStart に、以下を記述します。
![2022-08-11_09h05_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/74e45afb-75bc-8372-2be4-9ebf42539cc1.png)
~~~
Clear(SelectScreen);
ForAll([画面Ａ,画面Ｂ,画面Ｃ],Collect(SelectScreen,ThisRecord))
~~~
注意は、ForAllの最初の引数で画面Aから画面Cの配列を渡していますが、この要素は引用符で囲まないことです。
それによって、Screenコントロールの名前ではなく、Screenコントロール自体を配列の要素として指定します。
### Dropdownコントロール
続いて、Dropdownコントロールのソースを指定します。
DropdownコントロールのItemsプロパティにSelectScreenコレクションを指定
![2022-08-11_09h09_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/4e4debf9-a60f-4520-fd74-dd15bf286955.png)
「別のコレクション レコードの構造体が必要です。」と怒られました。
SelectScreen.Valueを渡しても、･･･
![2022-08-11_09h10_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/16875ee3-8c4c-a775-ee54-1aecce3b1cbd.png)
やっぱりダメ。
### Comboboxコントロールならどうだ？
新たにCombobox コントロールを配置して、ItemsプロパティにSelectScreen.Valueを設定。
エラーにはならないが、･･･
![2022-08-11_09h17_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/0e0a9a79-8ec8-9079-8f47-a1a2b928d49e.png)
ドロップダウンに表示されない、･･･。
![2022-08-11_09h17_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/9d4dc036-39a4-fa04-497d-af64174508b7.png)
３個あるので、何やら３つは入っているらしい。
Labelコントロールで確認すると、
![2022-08-11_09h21_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/0b2a8de6-b0c2-42fd-7ddf-8f38c64b7c0e.png)
確かにScreenコントロールが入っている。
ちなみにButtonコントロールにNavigate関数を書くと、動作します。
![2022-08-11_09h24_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/73aa8b5f-2448-a207-41ce-5ebfbacfa80f.png)
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/d6b175fa-21de-45f5-5568-7771309bef99.gif)

## 修正
Comboboxを使ったやり方で動作はするものの、DisplayFieldを弄ったりしてもどうにも表示が見えないので、少しやり方を変えます。
### App の OnStart を修正
OnStart の動作を修正し、SelectScreenコレクションに、NameとControlという２つのプロパティを持つレコードを格納してやるようにします。
![2022-08-11_09h42_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/beecda32-f7c0-b575-6e94-07f9aaeee740.png)
~~~
Clear(SelectScreen);
ForAll([画面Ａ,画面Ｂ,画面Ｃ],Collect(SelectScreen,{Name:ThisRecord.Value.Name,Control:ThisRecord.Value}))
~~~
DropdownやComboboxのソース（Itemsプロパティ）は、SelectScreen.Valueではなく、SelectScreenを設定
![2022-08-11_09h50_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/4df47eb7-10e0-d6ac-f785-4a4ef79b9c47.png)
Dropdownのソースを修正すると、何やら表示されました。
ComboboxもソースをSelectScreen.ValueからSelectScreenに修正すると項目名が正しく表示されるようになります。
下図で [object Object]とか表示されているのは、修正前に選択した状態が残っているためです。
プレビューで、[object Object] を×で選択解除すると、これ以降は出てきません。
![2022-08-11_09h52_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/8d5017e8-7bfd-b04c-68dd-4e02f8fd5a71.png)
### ほかの場所も修正して完成
DropdownでもComboboxでも（あるいはほかのコントロールでも）、スクリーンを選択できるようになります。
いちいち選択して、ボタンをクリックするのは面倒なので、それぞれのコントロールのOnChangeプロパティに、Navigate関数を記述していきます。
先ほどボタンのOnSelectに記述したのは、[Control名].Selected.Valueでしたが、[Control名.Selected.Controlになります。
ソース（Itemsプロパティ）は、SelectScreenコレクションになります。
![2022-08-11_10h09_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/96b3a31b-a713-aa7f-8ed1-f68251736b14.png)
### 動作確認
ついでにRadioボタンもつけてみました。
いづれの方法でも、選択した画面に遷移できることが確認できると思います。
![Animation1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244231/54f4cc88-28db-a800-ead4-ce8d396ea29c.gif)

## まとめ
ポイントは以下の通りです。
1. OnStartで、NameとControlの２つのプロパティを持ったScreenコントロールのコレクションを作成する
2. 遷移先の選択用コントロールのItemsプロパティに、Screenのコレクションを指定する
3. 選択用コントロールのValueやDisplayNameに、ScreenコレクションのNameプロパティを指定する
4.  選択用コントロールのOnChangeに、Navigate関数を記述して、第一引数に"Self.Selected.Control"を指定する。（別にボタンを用意しても可）

このようなやり方をしなくても、Switch関数とかで場合分けして遷移先を選んでやれば、これと同じ動作をさせることはなんぼでもできます。
ただ、画面が今後も増えていったり、遷移する方法を変えたりといったことがあるたびに、Itemsプロパティを修正したり、Navigate関数を修正したりするのは、修正漏れが出てきたりしてメンテナンス性がかなり悪くなります。
このやり方だと、スクリーンの追加をした場合でもコレクションに追加するだけで、Dropdown等のコントロールを修正する必要はなくなります。
なので、画面の追加や修正がかなり楽になるのではないでしょうか。
（迷路ゲームとか脱出ゲームに使えそうな気がします。作りませんが...）