Power Apps コンポーネントを活用して、開発効率を上げよう！（自作メッセージボックス）応用編

:::note
2024.01.22
**降りてきた！！**
:::

**Toggleで、不安定性を解決したバージョン！**

# はじめに
今回は[こちらの記事](https://qiita.com/DEmodoriGatsuO/items/c0030ead94a1bec867f1)の続きで、コンポーネントでメッセージボックスを作っていきます。

https://qiita.com/DEmodoriGatsuO/items/c0030ead94a1bec867f1

[VBAのMsgBox 関数](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function)の機能を再現してみます。

## VBAのMsgBox 関数
まずは、[VBAのMsgBox 関数](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function)をおさらいしましょう。
このような時は公式のlearnが一番ですね！

https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function

```
MsgBox (prompt, [ buttons, ] [ title, ] [ helpfile, context ])
```

`prompt` は前回の記事で紹介した通りですが、`buttons` そして、Msgboxの`戻り値`に焦点を当てて作っていきたいと思います。

:::note warn
[ helpfile, context ] は割愛します。
:::

### [buttons引数](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function)

[公式](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function#settings)を参照します。

https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/msgbox-function#settings

- **ボタンの種類**
- **メッセージボックスのアイコン**
- システム モーダル
- ヘルプ
- 文字の右揃えの設定

上記が設定で入り混じっているように感じます。（個人の感想です）

このうち、`ボタンの種類`と`メッセージボックスのアイコン`を下記のようにして再現します。

:::note warn
ほかのところはごめんなさい🙇
:::

|再現方法|データ型|説明|
|---|---|---|
|ボタン|テーブル型|Lookupで配列を表示|
|アイコン|テーブル型|指定したアイコンをそのままコンポーネントに渡す、かつ色も指定|
|デフォルト|整数|列挙型が好きな場合は、カスタマイズしてください|


|定数|説明|
|---|---|
|pwOKOnly|OK のみ
|pwOKCancel|OK、キャンセル
|pwAbortRetryIgnore|中止、再試行、無視 
|pwYesNoCancel|はい、いいえ、キャンセル 
|pwYesNo|はい、いいえ 
|pwRetryCancel|再試行、キャンセル

### アイコンの設定
関数に着眼すると、
- vbCritical
- vbQuestion
- vbExclamation
- vbInformation

四つの種類のアイコンが存在します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e6231289-4bd7-2786-4b03-6794d9ad041a.png)

今回は、値の部分を割愛し、文字列からアイコンを設定するようにします。
なお、画像を追加する意味も特にないと思っているので、Power Appsの組み込みのアイコンで対処します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/3de89d5a-eb91-c1d9-7734-b444138a2b2c.png)

|定数|値|説明|
|---|---|---|
|pwCritical|16|重大なメッセージ アイコン
|pwQuestion|32|警告クエリ アイコン
|pwExclamation|48|警告メッセージ アイコン
|pwInformation|64|情報メッセージ アイコン

### 戻り値
クリックしたボタンに応じて、戻り値を設定します。
こちらは`レコード型`で、テキストも定数も値も返す形にしましょう。

|テキスト|定数|値|
|---|---|---|
|OK|pwOK|1|
|キャンセル|pwCancel|2|
|中止|pwAbort|3|
|再試行|pwRetry|4|
|無視|pwIgnore|5|
|はい|pwYes|6|
|いいえ|pwNo|7|

```plaintext:値のテーブル
Table(
    { Text:"OK", Enum:"pwOK", Value:1},
    { Text:"キャンセル", Enum:"pwCancel", Value:2},
    { Text:"中止", Enum:"pwAbort", Value:3},
    { Text:"再試行", Enum:"pwRetry", Value:4},
    { Text:"無視", Enum:"pwIgnore", Value:5},
    { Text:"はい", Enum:"pwYes", Value:6},
    { Text:"いいえ", Enum:"pwNo", Value:7}
)
```

上記の中から`Lookup`でデータを抜き出して取得します。

:::note
別にいらないな、と思う部分は、ガンガン削ってください。
:::

# コンポーネントをカスタマイズする
文字を出す前に、完成系の[YouTube](https://youtu.be/T7cuxfuCMBw)と、[Power Apps](https://github.com/DEmodoriGatsuO/PowerPlatform-Events-Sample/tree/main/99Qiita/PowerAppsMsgbox20240121)を載せておきます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/T7cuxfuCMBw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

https://github.com/DEmodoriGatsuO/PowerPlatform-Events-Sample/tree/main/99Qiita/PowerAppsMsgbox20240121

## 入出力
まずはコンポーネントに渡す`カスタム プロパティ`を下記のとおり、設定しました。

### ■ 入力
|Name|データ型|値の説明|
|---|---|---|
|MsgBoxTitle|テキスト|メッセージボックスのタイトル|
|MsgBoxPrompt|テキスト|メッセージボックスの文章|
|pwMsgBoxStyle|テキスト|`MsgBoxButtons`のキー値|
|pwIconStyle|テキスト|`MsgBoxIconStyle`のキー値|

- 下記は削除！ 2024.01.22

|Name|データ型|値の説明|
|---|---|---|
|~~MsgBoxButtons~~|~~レコード~~|~~メッセージボックスのボタンを設定~~|
|~~MsgBoxIconStyle~~|~~レコード~~|~~アイコンの設定~~|

:::note
カスタム プロパティは`表示名`、`名前`が存在しますが、
作者は英語で、かつ内容も全て統一しています。
:::

### ■ 出力
|Name|データ型|値の説明|
|---|---|---|
|DialogVisible|ブール値|メッセージボックスの表示・非表示を制御|
|MsgBoxResult|レコード|クリックしたボタンから値を出力|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/25f1b577-c7d3-a38e-8645-ecc6d1b4a21c.png)

## 1. トグル ボタンの追加
課題であった`入力変数`から計算した値によるコントロールの設定を解決するため、
**トグル ボタン** を採用します。

`MsgBox`の`Visible`がtrueになったときに動作する、
疑似的な`OnVisible`にします。

|項目|値|説明|
|---|---|---|
|コントロール名|tgVisible|ダジャレ|
|Default|MsgBox.Visible|コンポーネントのVisibleと連動させます。これで`OnChange`が発火します|
|Visible|false|非表示にしましょう|

```plaintext:OnChange
// MsgBoxコンポーネントが表示されたときに
If(MsgBox.Visible,
    // ボタンのレコードを取得
    Set(varButtons,
        LookUp(
                Table(
                {
                    Constant: "pwOKOnly",
                    Buttons: [
                        "OK"
                    ],
                    Description: "OKボタンのみ"
                },
                {
                    Constant: "pwOKCancel",
                    Buttons: [
                        "OK",
                        "キャンセル"
                    ],
                    Description: "OK、キャンセル"
                },
                {
                    Constant: "pwAbortRetryIgnore",
                    Buttons: [
                        "中止",
                        "再試行",
                        "無視"
                    ],
                    Description:"中止、再試行、無視"
                },
                {
                    Constant: "pwYesNoCancel",
                    Buttons: [
                        "はい",
                        "いいえ",
                        "キャンセル"
                    ],
                    Description: "はい、いいえ、キャンセル"
                },
                {
                    Constant: "pwYesNo",
                    Buttons: [
                        "はい",
                        "いいえ"
                    ], Description: "はい、いいえ"
                },
                {
                    Constant: "pwRetryCancel",
                    Buttons: [
                        "再試行",
                        "キャンセル"
                    ],
                    Description: "再試行、キャンセル"
                }
            ),
            // キー値は入力されたpwMsgBoxStyleから
            Constant = MsgBox.pwMsgBoxStyle
        )
    );
    // アイコンのレコードを取得
    Set(varIconStyle,
        LookUp(
            Table(
                { pwIconStyle:"pwCritical", Icon:Icon.CancelBadge, Color:RGBA(255,0,0,1), Visible: true, Description:"重大なメッセージ"},
                { pwIconStyle:"pwQuestion", Icon:Icon.Help, Color:RGBA(0,134,208,1), Visible: true, Description:"警告クエリ"},
                { pwIconStyle:"pwExclamation", Icon:Icon.Warning, Color:RGBA(255,191,0,1), Visible: true, Description:"警告メッセージ"},
                { pwIconStyle:"pwInformation", Icon:Icon.Information, Color:RGBA(0,134,208,1), Visible: true, Description:"情報メッセージ"}
            ),
            // キー値は入力されたpwIconStyleから
            pwIconStyle = MsgBox.pwIconStyle
        )
    )
)
```

:::note 
疑似的 OnVisibleで変数を更新！
動的なメッセージボックスを再現できます！
:::

## 2. アイコンの追加
[前回の記事](https://qiita.com/DEmodoriGatsuO/items/c0030ead94a1bec867f1)との差分はアイコンの存在です。

メッセージが表示される赤線の枠に、設定がされた場合、アイコンが出るように、
`Icon` コントロールを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e51332e1-3fb1-9600-6ba7-94eff4297948.png)

便利なことに`Icon`は`プロパティ`で表示を制御できます。合わせて`Color`も渡し、表示を似せていきましょう。

|項目|値|説明|
|---|---|---|
|Color|varIconStyle.Color|アイコンの色|
|DisabledColor|varIconStyle.Color|アイコンの色 - 無効にする場合|
|DisplayMode|DisplayMode.Disabled|見る専のものは無効に私はします|
|Icon|varIconStyle.Icon|レコードから組み込みのアイコンを取得|
|Visible|varIconStyle.Visible|アイコンなし用|


## 3. ボタン コントロール
~~コンテナにボタンを3つ設置し、`配列`の要素数でボタンの数、テキストをコントロールします。~~

`ギャラリー コントロール`を用意します！
中には`ボタン コントロール`を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/a9147fd2-be76-ca22-fbb1-d2fba6d09af7.png)

**配列からボタン数が決定します！**

**ギャラリー コントロール galButtons**

|項目|値|説明|
|---|---|---|
|Items|varButtons.Buttons|配列で要素を決定|
|TemplateSize|IfError(Self.Width / CountRows(varButtons.Buttons),96)|テンプレートのサイズ|
|Width|Parent.Width * 0.95|好みで|

**ボタン コントロール MsgBoxButton**
|項目|値|説明|
|---|---|---|
|Text|ThisItem.Value|テキストの値|
|Width|Parent.Width * 0.28|好みで幅を決める|
|X|(Parent.TemplateWidth / 2) - (Self.Width / 2)|縦方向に中央揃え|
|Y|(Parent.TemplateHeight / 2) - (Self.Height / 2)|垂直方向に中央揃え|

ボタンのOnSelectで出力値を制御します。
こちらの`Set`関数で定義した値が、出力値として返されます。

```plaintext:OnSelect
Set(Return,
    LookUp(
        Table(
            { Text:"OK", Enum:"pwOK", Value:1},
            { Text:"キャンセル", Enum:"pwCancel", Value:2},
            { Text:"中止", Enum:"pwAbort", Value:3},
            { Text:"再試行", Enum:"pwRetry", Value:4},
            { Text:"無視", Enum:"pwIgnore", Value:5},
            { Text:"はい", Enum:"pwYes", Value:6},
            { Text:"いいえ", Enum:"pwNo", Value:7}
        ),Text = Self.Text
    )
);
Set(MsgBoxVisible,!MsgBoxVisible);
```

## 既知の課題
 - ~~コンポーネント内のコントロールに、入力値から狙った値が反映されない~~
     - ~~テーブル、レコードに基づく、コントロールの設定が間に合わないケースが多くあります・・・~~
 - Notレスポンシブ対応
     - 横長の画面対応想定

# おわりに
使いまわしによって開発が加速できると、本当に素晴らしいですね！
~~Power Apps全然ﾜｶﾗﾝ・・・~~

天啓が下りると、超気持ちがいいですね！！

**良いPower Lifeを！**