7

我正在使用 MvvmCross 创建我的 Android 应用程序,但遇到了以下问题:

当我试图显示在 ViewModel 中创建的 AlertDialog 时,

出现“未处理的异常: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();
            });
    }
}

当我研究时,我发现它发生是因为对上下文的引用而不是在 AlertDialog.Builder 中的 Activity 上。

本主题中,我发现了以下决定:通过使用 GetService() 接收对当前 Activity 的引用,但我没有找到用于 IMvxServiceConsumer、IMvxAndroidCurrentTopActivity 接口的 mvvmcross 插件。

我的问题是我可以从 ViewModel 显示 AlertDialog 吗?以及如何获得对 Activity 的引用,而不是对 Application.Context 的引用?关闭用户将留在当前视图上的 AlertDialog 的正确方法是什么?

4

1 回答 1

14

一般来说,你应该尽量不要把这种类型的代码放到 ViewModels 中

  • 因为 ViewModel 应该保持平台独立
  • 因为 ViewModel 应该是可单元测试的 - 当代码显示对话框时很难进行单元测试

我还建议您不要将这样的代码放在 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();

MvvmCross : How IMvxAndroidCurrentTopActivityto pass Android context down to MvxCommand?

该问题/答案中采用的方法也是我通常会从 ViewModel 显示对话框的方法之一:

  • 我会创建一个IFooDialog界面
  • 理想情况下,我可能会使这个接口异步 - 例如使用async或使用Action<DialogResult>回调参数
  • 在每个平台上,我都会在 UI 项目中实现它
  • ViewModel然后可以在需要对话框时使用 s ,IFooDialog并且每个平台都可以使用适当的 UI 操作进行响应

这种“对话服务”类型的方法在 Mvvm 中很常见 - 例如,请参阅http://www.codeproject.com/Articles/36745/Showing-Dialogs-When-Using-the-MVVM-Pattern之类的文章(尽管那篇文章非常特定于 Windows!)

这里还有一些关于 MvvmCross 和对话框的其他问题 - 尽管它们可能包含对旧 v1 或 vNext 代码的引用 - 例如,MvvmCross 中的警报或弹出窗口以及无法运行 ProgressDialog - BadTokenException while showind

于 2013-06-11T06:36:49.663 回答