通过后退按钮取消 MvxAppCompatDialogFragment 不完全有效

MvxAppCompatDialogFragment cancellation via Back button is not completely working

通过后退按钮关闭 MvxAppCompatDialogFragment 似乎并不完全有效。关闭对话框后,我单击以触发对话框的按钮仍处于禁用状态。这几乎就像 Task 被卡住了。如果我更改为 MvxDialogFragment 然后后退按钮将按预期关闭对话框,并且我单击以触发对话框的按钮在对话框关闭后再次启用。我正在尝试使用 MvxAppCompatDialogFragment,因为我正在使用 MvxAppCompatActivity。我做错了什么或者这是 MvvmCross 5.2.1 中的错误?

这是视图模型:

public class ConfirmationViewModel : MvxViewModel<ConfirmationConfiguration, bool?>, IMvxLocalizedTextSourceOwner
{
    private readonly IMvxNavigationService _mvxNavigationService;

    public ConfirmationViewModel(IMvxNavigationService mvxNavigationService)
    {
        _mvxNavigationService = mvxNavigationService;
    }

    public override void Prepare([NotNull] ConfirmationConfiguration parameter)
    {
        if (parameter == null) throw new ArgumentNullException(nameof(parameter));
        Title = parameter.Title;
        Body = parameter.Body;
        PositiveCommandText = !string.IsNullOrEmpty(parameter.YesCommandText) 
            ? parameter.YesCommandText 
            : LocalizedTextSource.GetText("Yes");
        NegativeCommandText = !string.IsNullOrEmpty(parameter.NoCommandText)
            ? parameter.NoCommandText
            : LocalizedTextSource.GetText("No");
    }

    private bool? _confirmationResult;
    public bool? ConfirmationResult
    {
        get => _confirmationResult;
        private set => SetProperty(ref _confirmationResult, value);
    }

    private string _title;
    public string Title
    {
        get => _title;
        set => SetProperty(ref _title, value);
    }

    private string _body;
    public string Body
    {
        get => _body;
        set => SetProperty(ref _body, value);
    }

    private string _positiveCommandText;
    public string PositiveCommandText
    {
        get => _positiveCommandText;
        set => SetProperty(ref _positiveCommandText, value);
    }

    private string _negativeCommandText;
    public string NegativeCommandText
    {
        get => _negativeCommandText;
        set => SetProperty(ref _negativeCommandText, value);
    }

    private IMvxAsyncCommand _yesCommand;
    public IMvxAsyncCommand PositiveCommand => _yesCommand ?? (_yesCommand = new MvxAsyncCommand(OnPositiveCommandAsync));

    private async Task OnPositiveCommandAsync()
    {
        ConfirmationResult = true;
        await _mvxNavigationService.Close(this, ConfirmationResult);
    }

    private IMvxAsyncCommand _noCommand;
    public IMvxAsyncCommand NegativeCommand => _noCommand ?? (_noCommand = new MvxAsyncCommand(OnNegativeCommandAsync));

    private async Task OnNegativeCommandAsync()
    {
        ConfirmationResult = false;
        await _mvxNavigationService.Close(this, ConfirmationResult);
    }

    public IMvxLanguageBinder LocalizedTextSource => new MvxLanguageBinder("", GetType().Name);

    public IMvxLanguageBinder TextSource => LocalizedTextSource;
}

public class ConfirmationConfiguration
{
    public string Title { get; set; }
    public string Body { get; set; }
    public string YesCommandText { get; set; }
    public string NoCommandText { get; set; }
}

视图如下:

[MvxDialogFragmentPresentation(Cancelable = true)]
[Register(nameof(ConfirmationFragment))]
public class ConfirmationFragment : MvxAppCompatDialogFragment<ConfirmationViewModel>
{
    public ConfirmationFragment()
    {
        RetainInstance = true;
    }

    public ConfirmationFragment(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
        RetainInstance = true;
    }

    public override Dialog OnCreateDialog(Bundle savedInstanceState)
    {
        var builder = new AlertDialog.Builder(Activity)
            .SetTitle(ViewModel.Title)
            .SetMessage(ViewModel.Body)
            .SetPositiveButton(ViewModel.PositiveCommandText, OnPositiveButton)
            .SetNegativeButton(ViewModel.NegativeCommandText, OnNegativeButton);
        return builder.Create();
    }

    private async void OnNegativeButton(object sender, DialogClickEventArgs e)
    {
        if (ViewModel.NegativeCommand.CanExecute())
        {
            await ViewModel.NegativeCommand.ExecuteAsync();
        }
    }

    private async void OnPositiveButton(object sender, DialogClickEventArgs e)
    {
        if (ViewModel.PositiveCommand.CanExecute())
        {
            await ViewModel.PositiveCommand.ExecuteAsync();
        }
    }
}

我正在导航到这样的对话框:

        var confirmation = await Mvx.Resolve<IMvxNavigationService>().Navigate<ConfirmationViewModel, ConfirmationConfiguration, bool?>(
            new ConfirmationConfiguration()
            {
                Body = "Hello, World!",
                Title = "Testing"
            });

如果我将基数 class 从 MvxAppCompatDialogFragment 更改为 MvxDialogFragment 那么一切都会按预期工作。

我已经调查过了。发生的情况是,当您按下后退按钮时,它会在不调用 NavigationSerivce.Close() 的情况下关闭视图。这可以防止调用结果 Task 并设置或取消操作。我不确定这是错误还是只是行为。解决方法是从 ConfirmationViewModel ViewDissapearing 调用 Close,或者自己取消 Task

这确实是 MvvmCross v5.2.1 中的一个问题(感谢报告!)。作为目前的解决方法,您可以在 DialogFragment class:

中添加此代码
public override void OnCancel(IDialogInterface dialog)
{
    base.OnCancel(dialog);
    ViewModel?.ViewDestroy();
}

public override void DismissAllowingStateLoss()
{
    base.DismissAllowingStateLoss();
    ViewModel?.ViewDestroy();
}

public override void Dismiss()
{
    base.Dismiss();
    ViewModel?.ViewDestroy();
}