【Power Apps】Print関数を使用して1画面で複数ページ印刷する方法

## はじめに
Power Apps には、表示画面を印刷するための「Print関数」があります。しかし、この関数は**表示されている画面をそのまま印刷する**仕様となっており、コントロールを展開して複数ページに渡って印刷するという器用なことはできません。例えば、ギャラリーのような動的コンテンツを含む印刷画面の場合、その内容（行数）に応じて必要となるページ数が変化しますが、Print関数で印刷できるのは画面に表示されているその1ページのみです。そこで、**ギャラリーを含む印刷画面において、1画面で複数ページを印刷する方法を実装および一般化**したので、備忘録として残しておきます。

## アイデア
この記事で考える画面の構成は、最初のページでのみ印刷するヘッダーコンテナ、ギャラリーを含むメインコンテナ、最後のページでのみ印刷するフッターコンテナの3つになります。このとき、本来であれば画面に収まりきらないギャラリーを適当に分割し、ページングの要領でその画面に表示するコンテナとギャラリーを切り替えることで1画面での複数ページ印刷を実現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478860/af58af6a-76e5-b530-5eea-537e33e5b76d.png) 
## 作成したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478860/65462b6d-aa53-2d65-27b0-f836dbcd88ed.png)

## 実装
#### 画面構成
画面構成と使用コントロールについては、添付画像のツリービュー（左側）を参考にしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478860/e4178424-5d79-c065-ce41-bf8a4b2da82d.png)

#### コード
１. 印刷画面のOnVisibleで以下の変数を設定
``` : 印刷画面: OnVisible
// コンテナの高さ÷ギャラリーの行の高さ により各コンテナに対応する行数を定義
UpdateContext({locExtraRowsWithoutHeader: RoundDown(ctnヘッダー.Height / galサンプル.TemplateHeight, 0)});
UpdateContext({locBasicRowsPerPage: RoundDown((ctn印刷.Height - (lblスペース.Height + ctnヘッダー.Height + ctnサンプルラベル.Height + ctnフッター.Height)) / galサンプル.TemplateHeight, 0)});
UpdateContext({locExtraRowsWithoutFooter: RoundDown(ctnフッター.Height / galサンプル.TemplateHeight, 0)});

// ページ数と行数の範囲を初期化
UpdateContext({locPageNumber: 1});
UpdateContext({locLowerLimitRows: 0});
UpdateContext({locHigherLimitRows: locBasicRowsPerPage + locExtraRowsWithoutFooter}); // 1ページ目はヘッダーが表示されるためギャラリーの行数の上限はこの2つの和

// ギャラリーに表示するサンプルアイテム（75行）
UpdateContext({locサンプル: ForAll(Sequence(75), {RowNumber: Value})})
```

２. 表示切替アイコンのOnSelectとVisibleを設定
``` : ico次ページ: OnSelect
UpdateContext({locPageNumber: locPageNumber + 1});
UpdateContext({locLowerLimitRows: locHigherLimitRows});
UpdateContext({locHigherLimitRows: locHigherLimitRows + (locBasicRowsPerPage + locExtraRowsWithoutHeader + locExtraRowsWithoutFooter)}) // 2ページ目からはヘッダーが表示されないためこの3つの和だけ増加
```
``` : ico次ページ: Visible
// フッターが非表示かつ印刷中でない場合のみ表示
!ctnフッター.Visible && Not(印刷画面.Printing)
```
``` : ico前ページ: OnSelect
// ico次ページと逆の処理
UpdateContext({locPageNumber: locPageNumber - 1});
UpdateContext({locHigherLimitRows: locLowerLimitRows});
UpdateContext({locLowerLimitRows: locLowerLimitRows - (locBasicRowsPerPage + locExtraRowsWithoutHeader + locExtraRowsWithoutFooter})

If(locLowerLimitRows < 0, UpdateContext({locLowerLimitRows: 0}))
```
``` : ico前ページ: Visible
!ctnヘッダー.Visible && Not(印刷画面.Printing)
```

３. ギャラリーのItemsとHeightを設定
``` : galサンプル: Items
Filter(
    locサンプル, 
    RowNumber > locLowerLimitRows, 
    RowNumber <= locHigherLimitRows
)
```
``` : galサンプル: Height
// ギャラリーの行の高さ*行数 によりコンテナの高さを設定
galサンプル.TemplateHeight * 
If(
    CountRows(locサンプル) > locHigherLimitRows, 
    locHigherLimitRows - locLowerLimitRows, 
    CountRows(locサンプル) - locLowerLimitRows
)
```

４. メインコンテナのHeightを設定
``` : ctnメイン: Height
galサンプル.Y + galサンプル.Height
```

５. ヘッダーコンテナとフッターコンテナのVisibleを設定
``` : ctnヘッダー: Visible
// 1ページ目であればヘッダーコンテナを表示
If(
    locPageNumber = 1, 
    true, 
    false
)
```

``` : ctnフッター: Visible
// メインコンテナの終了位置＋フッターコンテナが画面からはみ出なければ表示
If(
    ctnメイン.Y + ctnメイン.Height + Self.Height > Parent.Height,
    false,
    true
)
```

## おわりに
今回は、ギャラリーを含む印刷画面において、1画面で複数ページを印刷する方法について紹介しました。1度作っておくと好みのヘッダー・フッターコンテナの高さに合わせてさまざまな印刷画面に応用できるので、ぜひ試してみてください。また、試験段階ではありますが、引数を指定することで**該当するコントロールが展開されたPDFオブジェクトを生成する**「PDF関数」というものもあります。早く運用環境で使用できるようになるのが待ち遠しいですね。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-pdf