おはようございます、こんにちは、こんばんは。先日は学習アプリ作成会にご参加いただきありがとうございました。今回もレポートとして記事を投稿いたします。分かりにくかった点は以下の動画#4をご覧ください。
また、記事に誤りがあった場合は、優しくご指摘いただけますと幸いです。なお、この記事は筆者が一方的に書いているものなので、文責はkuro.が負うものです。ご理解いただけますと幸いです。
動画#4
120分ほどある動画を編集するのって大変なんですよね…。10分ですら大変なのですが、今回もお忙しい中…。チャンネル登録、高評価で応援よろしくお願いします!
学習アプリ作成会で使用した関数は、ようさんのチャンネルで『関数解説シリーズ』としてリリースされています。チャンネル登録、高評価よろしくお願いします!
前回の復習(#3)
復習に関しては動画を視聴していただくか、当ブログの『Power Platform学習アプリ作成会#3』をお読みいただければと思います。Akiraさんのチャンネルは高評価と登録をよろしくお願いします。
今回(#4)の目指すところ

#4では、①10問の解答を終えた時にポップアップ表示される画面を作成し、②解答結果をSharePointリストに保存する(=成績登録)ところまで取り組みます。以下、具体的に確認していきましょう。
ポップアップ画面の作成
半透明の四角形の上に各コントロールを配置

まず、画面左手のツリービューのようにコントロールを配置します。以下に箇条で示します:
- btnRegister
- SharePointリストにテスト結果を登録するためのボタン。OnSelectプロパティに書くコードは以下で詳説
- galWrongAnswer
- テスト結果を保持しておくためのギャラリー
- Itemsプロパティ(データソース)は、colAnswer の TF フィールドの中から false のレコードを Filter関数 で抽出する。コードは次の通り:Filter(colAnswer,TF=false)
- 背景色を塗りつぶす(薄いグレーがいいかも)
- shpRim
- 四角形をギャラリーテンプレートと同じ大きさで重ねる
- 塗りつぶしを透明にする
- 罫線を任意の太さにする(1ptくらいが良さそう)
- lblWrongListE
- Textプロパティに ThisItem.correctAnswer を入力
- 間違えた英単語っぽく赤字にする
- 背景は透明色に
- lblWronglistJ
- Textプロパティに ThisItem.correctQuestion を入力
- 背景は透明色に
- icoClear
- OnSelectプロパティに Clear(colAnswer)を入力
- lblMessage
- とりあえず今は労をねぎらう言葉を書いておいてください。今後「正答数は○でした!」という感じで表示されるようにしても面白そうですね。
- shpPopUp
Fillプロパティに RGBA(215, 223, 240, 0.9) と書く。
半透明であれば色は好みで良い。
ポップアップ画面のコントロール群ということで、グループ化しておく方が良さそうです。そうすれば後で編集しやすくなりますね。
余談ですが、”rim” という単語は「円形の縁」を表す語なので、”edge” か “border” を使う方がいい気がしました。咄嗟に思い浮かんだのがこの単語だったので仕方ない。
Count, CountIf, CountRows関数

全ての Visibleプロパティに colAnswerのレコード数が10件に達したらコントロール(=ポップアップ画面)を表示する…という式を書きます。ここで必要になるのが、前回学習したIf関数と、レコード数をカウントするCountRows関数です。
If(CountRows(colAnswer)=10,true,false)
裏技ですが、上の画像のように同じ数式を入れたければ、対象のコントロールを全て選択した状態であれば、Visibleプロパティに一括でコードを書くことができます。
ここは変数 1 で処理するほうがキレイになると思いますが、今回は上のコードを選択した全てのVisibleプロパティに入れました。気になる人はやってみましょう。
【余談と気付き】
コードそのものは上の通りになりますが、今後「得点を集計したい」というような場合でも使える便利な関数だと思います。データソースに別途で配点フィールドを作成しておくか、アプリ内で計算式を書いておくかしておけば、Count系の関数を使って集計できそうです。

Patch関数で一括登録
「Patch関数を使ったら一括登録できる」というところまでは考えつくものの、関連の開発ブログを読んでもコードを書けない方々が多いかと思います。私のことなんですけど
個人的に、Patch関数で一括登録できるようになるためのコツは「段階を踏む」ことだと考えています。言い換えると、まずは「一件登録できる」ことを目指し、その後で「繰り返し処理できる」ことを目指すようにすると上手く行きます(たぶん)
今回の記事では、Patch関数、First関数、そして最後にForAll関数…という手順を踏むようにしましょう(以前、理解の助けになった七草あんこ先生の記事もご参考ください:https://anko7793.com/2022/04/1182/)
登録先(SharePointリスト)を作成する
Patch関数は、どこに登録するのかを指定しなければなりません。今回は、その保存先としてSharePointリスト English_Result を作成しました。

SharePointリストの作成と設定について細かいことを言い出したら1本記事が書けてしまうので、ふらりさんのスライドを紹介しておきます。ご参考ください。
Patch関数とForAll関数で一括登録

SharePointリストを作成したらアプリ作成画面に戻り、前回学習したFirst関数を組み合わせ、colAnswer(=自分の解答)のレコードを1件ずつ登録してみます。
初心者が整理しておいた方がいいポイントは、「{カーリーブラケット} の中に入るものが、それぞれフィールド名とレコードになる」ということです。上のSharePointリストの画像と照らし合わせると良いでしょう。ちなみに、自然言語で説明すると以下のようになります。
Patch ( 保存先のデータソース, {フィールドA : レコードA, フィールドB : レコードB, … } )
この時の「フィールドA」や「フィールドB」は、それぞれSharePointリストに登録されるフィールドです。
現時点では、SharePointリストを作成しただけになっているので、レコードをどこに格納するのかはPatch関数の中で示してあげる必要があります。ココ大事。
箇条にして整理してみましょう:
- colAnswerで作成したフィールド名
- correctQuestion
- correctAnswer
- myAnswer
- TF
- English_Resultで作成したフィールド名
- TrueQuestion
- TrueAnswer
- TrueAnswer
- TorF
自分の解答(colAnswer)を、成績表(English_Result)に格納するので、両者が対応する形でフィールドを作ってあげればOKです。
ここを整理できていないと、一括登録までたどり着かないと思います。まずは落ち着いて「どのレコードをどこに格納したいのか」を整理しましょう。
最後に、First関数で書いていた部分を、ForAll関数でループ処理し、以下のように書き換えてあげれば一括登録完了です。
ForAll関数の第一引数は「登録元データ」なんですね…。元データに何度も当たって登録先にPatchしてもらうのだから、当たり前といえば当たり前です。でも、混乱してしまいます。
ForAll(
colAnswer,
Patch(
English_Result,
{
Title:"",
TrueQuestion: correctQuestion,
TrueAnswer: correctAnswer,
FalseAnswer: myAnswer,
TorF: TF
}
)
)
まあ、要するに「Patch関数の処理を何回もやってくれ(今回は10件分)」ということなので、ForAll関数の説明は関数おじさんの動画に頼ることにしましょう。更新が楽しみですね。

余談:Patch関数でデータを更新する
登録するデータと、登録先のデータの2つが整理できていれば、一括更新も難しいものではありませんでした。Patch関数はまだまだ使い方によっては難度が高くなるようですが、お二方のおかげで基礎はできたように思います。

理解できていれば、colA のTitleフィールド、Value1フィールド、Value2フィールド、Value3フィールドに格納されたレコードを下のように更新することもできるようになります。

ようさんの関数説明アプリは自分の環境だと編集画面を開くことができないので、このアプリの挙動を見て書いてみました(間違えていたらご指摘ください~)
「Value3フィールドは数値しか入らない」というのをオンエア中に聞いたので、最後、文字列を数値に変換するためのValue関数が入っています。こうやってデータ型を指定して必要な情報を正確に入力してもらうのは大切ですよね。
Patch(
colA,
First(
Filter(
colA,
txtPatchUpdate.Text = Title
)
),
{
Value1: txtPatchUpdateValue1.Text,
Value2: txtPatchUpdateValue2.Text,
Value3: Value(txtPatchUpdateValue3.Text)
}
)
先ほどと同様、Patch( colA, First ( Filter( colA, txtPatchUpdate.Text = Title ) ) までが登録先のデータソースです。
少々乱暴ですが「Patch関数からカーリーブラケットの前までは登録先のデータソース」という理解で良いと思っています。その後、置き換えるレコードを指定してあげる…という流れです。ウーン。ムズカシイ。
これもForAll関数で一括更新できると思います。今回はやっていませんが、Patch関数を括ってあげれば成立するはず。慣れるまでは一つずつ、を徹底したいですね。
次回(#5)に向けて

やはり一気に理解しようとすると頭がパニックになりますね。
自分の学習能力が低いだけなのですが、いわゆる「入れ子構造」になると大きなまとまりを見失ってしまいます。
今回の場合は、Patch (登録先のデータソース), {そのフィールド名 : 登録したいレコード}) が、比較的、分かりやすかったので事なきを得た気がしています。
とにかく「落ち着いて1つずつ処理」が習得の鍵を握っていると改めて感じた次第です。次回もよろしくお願いします!

- UpdateContext, Set関数の説明はコチラの記事をご覧ください