Search code examples
androidmvvmxamarin.androidmvvmcrossandroid-dialogfragment

Binding MvxDialogFragment with ViewModel


I have ViewModel and DialogFragment for view this VM. In core I show VM in this way

this.ShowViewModel<AnnotationEditViewModel>();

i have this code in AnnotationEditDialogFragment.cs

[Register("AnnotationEditDialogFragment")]
public class AnnotationEditDialogFragment : MvxDialogFragment<AnnotationEditViewModel>
{
...
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
base.EnsureBindingContextSet(savedInstanceState);
var view = this.BindingInflate(Resource.Layout.text_annotation_dialog_fragment, null);
var titleAnnotationTextView = view.FindViewById<TextViewWithFont>(Resource.Id.titleAnnotationTextView);
var set = this.CreateBindingSet<AnnotationEditFragment, AnnotationEditViewModel>();
set.Bind(this).For(be => be.CanBeSaved).To(vm => vm.CanBeSaved);
set.Apply();
builder = new AlertDialog.Builder(Activity);
LayoutInflater inflater = Activity.LayoutInflater;
builder.SetView(view);
alertDialog = builder.Create();
return alertDialog;
}
...
}

I have request in MainPresenter in Showv method where i can detect this request.

if in MainPresenter i type this code:

var textAnnotationDialogFragment = Activity.FragmentManager.FindFragmentByTag(nameof(AnnotationEditFragment)) as AnnotationEditFragment ?? new AnnotationEditFragment();
textAnnotationDialogFragment.Show(Activity.FragmentManager, nameof(AnnotationEditFragment));
  • I see dialog, but i don't have binding with VM/

if i type this code for ShowViewModel():

base.Show(request, fragmentRequest);
  • I get error that wasn't found any activity or fragment for my VM/ How can I have dialog with binding to VM?

Solution

  • The issues:

    1. Presenter Handled Request approach - ViewModel Null

    Using this approach the ViewModel property of AnnotationEditFragment is null as no ViewModel has been set on the fragment as it is being created outside of the normal lifecycle Mvx uses when creating normal MvxFragments. MvxDialogFragment follow a different lifecycle.

    2. Presenter Unhandled Request approach - No Activity

    Using this approach the standard Mvx fragment lifecycle is trying to be executed on the MvxDialogFragment. Which requires an Activity to be specified to place the fragment into. This is not the approach we want with the MvxDialogFragment.


    Solution:

    I believe approach 1 is the closest to getting us a successfully implementation of a working MvxDialogFragment. All we need to do is make sure the ViewModel runs through it's lifecycle. So in your MainPresenter make sure to create an instance of the AnnotationEditViewModel based on the request and assign it to the AnnotationEditFragment:

    protected override void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null)
    {
        if (request.ViewModelType == typeof(NamesViewModel))
        {
            var dialog = new AnnotationEditFragment();
            var viewModel = Mvx.Resolve<IMvxViewModelLoader>().LoadViewModel(request, null) as AnnotationEditViewModel;
            dialog.ViewModel = viewModel;
            dialog.Show(Activity.FragmentManager, nameof(AnnotationEditFragment));
    
            return;
        }
    
        base.ShowActivity(request, fragmentRequest);
    }
    

    IMvxViewModelLoader is used to make sure the ViewModel is loaded according to the Mvx ViewModel lifecycle standard, CIRS:

    1. Construction - using IoC for Dependency Injection
    2. Init() - initialisation of navigation parameters
    3. ReloadState() - rehydration after tombstoning
    4. Start() - called when initialisation and rehydration are complete