7

Android アプリの作成に MvvmCross を使用していますが、次の問題に直面しました。

ViewModel で作成した AlertDialog を表示しようとすると、

Unhandled Exception: Android.Views.WindowManagerBadTokenException」が表示されます。

public class MyViewModel : MvxViewModel
{
    public ICommand ShowAlertCommand { get; private set; }

    public AuthorizationViewModel()
    {
        ShowAlertCommand = new MvxCommand(() =>
            {
                var adb = new AlertDialog.Builder(Application.Context); 
                adb.SetTitle("Title here");
                adb.SetMessage("Message here");  
                adb.SetIcon(Resource.Drawable.Icon);
                adb.SetPositiveButton("OK", (sender, args) => { /* some logic */});   
                adb.SetNegativeButton("Cancel", (sender, args) => { /* close alertDialog */});

                adb.Create().Show();
            });
    }
}

私が調査していたとき、アラートダイアログ.ビルダーのアクティビティではなく、コンテキストへの参照の送信が原因であることがわかりました。

このトピックでは、次の決定を見つけました: GetService() を使用して現在のアクティビティへの参照を受け取りますが、IMvxServiceConsumer、IMvxAndroidCurrentTopActivity インターフェイスで動作する mvvmcross プラグインが見つかりませんでした。

私の質問は、ViewModel から AlertDialog を表示できますか? また、Application.Context ではなく Activity への参照を取得するにはどうすればよいですか? そして、ユーザーが現在のビューにとどまるという AlertDialog を閉じる正しい方法は何ですか?

4

1 に答える 1

14

一般に、このタイプのコードを ViewModel に入れないようにする必要があります。

  • ViewModel はプラットフォームに依存しない必要があるため
  • ViewModels は単体テスト可能である必要があり、コードがダイアログを表示するときに単体テストを行うのは難しいためです。

また、このようなコードを ViewModel コンストラクター内に配置しないことをお勧めします。これらのコンストラクターは通常、ナビゲーション中に呼び出され、遷移中にダイアログを表示すると問題が発生する可能性があります。


これらのことを踏まえて、任意のコード内で現在のトップ アクティビティを取得したい場合は、IMvxAndroidCurrentTopActivity

public interface IMvxAndroidCurrentTopActivity
{
    Activity Activity { get; }
}

これを使用すると、どのコードでも次を使用して現在の値を取得できますActivity

var top = Mvx.Resolve<IMvxAndroidCurrentTopActivity>();
var act = top.Activity;
if (act == null)
{
   // this can happen during transitions
   // - you need to be sure that this won't happen for your code
   throw new MvxException("Cannot get current top activity");
}

var dlg = new AlertDialog.Builder(act); 
//...
dlg.Create().Show();

の使用IMvxAndroidCurrentTopActivityについては、MvvmCross: How to pass Android context down to MvxCommand? で説明されています。

その質問/回答で採用されたアプローチは、ViewModel からダイアログを表示するために一般的にアプローチする方法の 1 つでもあります。

  • IFooDialogインターフェイスを作成します
  • 理想的には、おそらくこのインターフェイスを非同期にするでしょう-たとえば、コールバックパラメーターを使用asyncまたは使用しますAction<DialogResult>
  • 各プラットフォームで、UI プロジェクトでそれを実装します
  • は、ダイアログが必要なときにViewModel使用でき、各プラットフォームは適切な UI アクションで応答できます。IFooDialog

この「ダイアログ サービス」タイプのアプローチは、Mvvm で一般的です Windows 固有!)

ここには、MvvmCross とダイアログに関する他のいくつかの質問もあります。ただし、古い v1またはvNext コードへの参照が含まれている可能性があります

于 2013-06-11T06:36:49.663 に答える