Windowsでいうモーダルダイアログの様なAPI実装で、Pageの表示ができないか検討してみた。
「Windowsでいうモーダルダイアログの様なAPI実装」とはWin32 APIのDialogBoxを使うもの。
呼び出し側でDialogBoxを使うことで表示されたダイアログボックスで何かしらのアクション、実際には閉じる動作を行わないとDialogBoxの次の処理に進まないというもの。
連続した処理を実装できるので、コードが見やすくなるというか。
個人的には実装しやすいと思っている。
使う状況の画面の遷移例
Xamarinのサンプル(もしくは新規プロジェクトのテンプレート物)に入っている、CollectionViewでリスト表示して、リストをタップするとその詳細ページを表示するというもの。
CollectionViewに設定されている項目をタップすると、次のような詳細ページにジャンプする。
この例は編集不可の表示だけのページなのだけど、これに「設定」「取消」のツールバーを付けて、そのボタン押下の情報を親側に渡すといったもの。
こちらが選択画面。
例えばHistory 2をタップすると、以下の画面が表示され、表示する項目を編集でき「設定」「取消」ボタンでデータベースへの反映の指示が可能になるといった感じのもの。
実際に実装したソースは以下になる。
実装の説明
処理の肝の部分は、TaskCompletionSourceを使っているところ。
詳細画面側のViewModelにTaskCompletionSource<bool>を用意しておき、設定が押されたらTrueを、取消が押されたFalseを設定するようにしている。
それと同時にボタンが押されたら画面をもとに戻すようにしている。
それが以下の処理。
// 設定時のアクションと取消時のアクションを設定
DetailSet = new Command(() =>
{
Shell.Current.Navigation.PopAsync();
task_.SetResult(true);
});
DetailCancel = new Command(() =>
{
Shell.Current.Navigation.PopAsync();
task_.SetResult(false);
});
呼び出し側は次のようにしている。
var detail = new DetailViewModel()
{
Text = select_.HistoryTextTitle
};
var detailPage = new Views.DetailPage()
{
BindingContext = detail,
};
await Shell.Current.Navigation.PushAsync(detailPage);
if (await detail.Result) {
select_.HistoryTextTitle = detail.Text;
}
前半部分は詳細画面の用意。
その後それを表示(PushAsync)して、結果がTrueの場合、選択画面の表示項目を変更している。
ここで使っているDetailViewModel.Resultの実装は以下の様にしている。
public Task<bool> Result { get=> task_.Task; }
これにより、呼び出し側では詳細ページを呼び出しそのリターン値をもって処理を続行するような実装が行える。
補足
詳細画面で、NavigationPageの←を取消という名称に変更するためと、←が押されたら詳細画面側のViewModelにコマンドを呼び出すための実装にBackButtonBehaviorを使っている。
ただしこの機能UWPでは利用できなかった。
調べてみたら以下の様になっていた。
そのためUWPでは、←が押された場合の処理方法として、Page.Disappearingイベントが来たらViewModelのコマンドを呼び出し、そこでTask.Resultが呼び出されていない場合Flaseの設定、つまりキャンセル相当の状態にして返すようにしている。
UWPめんどくさいな。
コメント