Xamarin.Android モーダルダイアログへの誘惑
1 モーダルダイアログ
Windowsでデスクトップアプリを書いていると、当たり前のように「モーダルダイアログ」で処理を分岐して書いています。
本日は、Androidでモーダルダログを書こうと足掻いた記録です。
(1) Backボタンによるキャンセル
ダイアログボックスは、デフォルトで「BACK」キーを押すとキャンセル(クローズ)されます。
この動作を封じたい場合は、SetCancelable(false)と指定します。
SetCancelable()メソッドは、AlertDialogの基底クラスであるDialogの公開メソッドであり、DatePickerDialogなど、各種のダイアログの基底クラスでもありますので、すべてのダイアログで利用可能です。
(2) クローズ時のイベント
ダイアログは、クローズ時にDismisというイベントが発生しています。
そして、いくつかのダイアログでは、これをDismissEventというイベントや、SetOnDismissListener()メソッドで公開しています。したがって、このイベントをトラップすれば、ダイアログが閉じる際の処理は簡単です。
しかし、AlertDialogでは、何故かこれが隠ぺいされています。
AlertDialogを継承して、Dismisイベントを公開するMyAlertDialogを参考までに記録しておきます。
private void Func(){ var dlg = new MyAlertDialogDlg(this); dlg.SetTitle("タイトル"); dlg.SetMessage("メッセージ"); //ダイアログがクローズされた際のイベント処理 dlg.DismisEvent += (s, e) =>Toast.MakeText(this,"Dismis",ToastLength.Short).Show(); dlg.Show(); } //自前のAlertDialog public class MyAlertDialogDlg : AlertDialog{ public MyAlertDialogDlg(Context context): base(context){} //イベント定義 public event DismisEventDelegate DismisEvent; public delegate void DismisEventDelegate(object sender, EventArgs e); //Dismisイベントをオーバーライドしてイベントとして公開する public override void Dismiss(){ base.Dismiss(); if (DismisEvent != null){ DismisEvent(this, null); } } }
2 部品は揃った
ダイアログの生死イベントがハッキリしたので、「部品は揃った!」という事で、スレッド待機させようと色々悩んだのですが・・・Androidで、スレッドを待機させるという処理は、あまりお勧めでは無いようで、モーダルなダイアログを書こうとした途端に、コードがグタグタになってしまいます。
※特にUIスレッドの待機は不可能
(1) 結局やりたい事はコレだ
結局、下記のような書き方ができれば、一応OKという事で、スレッドを待機させない方向での解決に方向転換!
よーするに、こういう風に書きたいだけだ・・・
if (DialogResult.OK == MessageBox.Show("よろしいですか", "タイトル", MessageBoxButtons.OKCancel)) { //OKの時の処理 }
(2) ラムダ式でそれ風に
これでどうだろうか・・・下記のMessaegBoxクラスは、OKやCancelを押した時の処理を、delegateで受け取ります。
delegate void funcDelegate(); class MessageBox{ public static void Show(Context context, string msg, string title, funcDelegate Ok = null, funcDelegate Cancel = null){ var dlg = new AlertDialog.Builder(context); dlg.SetTitle(title); dlg.SetMessage(msg); dlg.SetPositiveButton( //OKボタンの処理 "OK", (s, a) => { if (Ok != null){ //func OKが指定されている場合、それを実行する Ok(); }}); dlg.SetNegativeButton( //Cancelボタンの処理 "Cancel", (s, a) => { if (Cancel != null){ //func Cancelが指定されている場合、それを実行する Cancel(); }}); dlg.Create().Show(); } }
使い方は、下記のとおりです。
MessageBox.Show(this, "よろしいですか", "タイトル", Ok:() => { //OKの時の処理 Toast.MakeText(this, "OK", ToastLength.Short).Show(); });
MessageBox.Show(this, "よろしいですか", "タイトル", Cancel:() => { //Cancelの時の処理 Toast.MakeText(this, "Cancel", ToastLength.Short).Show(); });
今日のあまりにも成果のない結論・・・「モーダルダイアログはやめとこう」