2

I am trying to use an MvxDialogFragment to show a data bound dialog from an activity. My Dialog ViewModel is as follows:

public class ContainerDialogViewModel : MvxViewModel
{

    public string ShipperName;

    public void Init(string Name)
    {
        ShipperName = Name;
        LoadData();
    }

    public void LoadData()
    {
        Survey = SurveyDataSource.CurrSurvey;
    }

    private ShipmentSurvey _Survey;
    public ShipmentSurvey Survey
    {
        get
        {
            return _Survey;
        }
        set
        {
            _Survey = value;
            RaisePropertyChanged(() => Survey);
            RaisePropertyChanged(() => Containers);
        }
    }


    public List<ShipmentSurveyContainer> Containers
    {
        get
        {
            if (Survey == null)
                return new List<ShipmentSurveyContainer>();
            else
                return Survey.SurveyContainers.ToList();
        }
    }

}

The MvxDialogFragment is coded as follows:

public class ContainerDialog : MvxDialogFragment<ContainerDialogViewModel>
{
    public override Dialog OnCreateDialog(Bundle savedState)
    {
        base.EnsureBindingContextSet(savedState);

        this.BindingInflate(Resource.Layout.ContainerDialog, null);

        return base.OnCreateDialog(savedState);
    }

}

In my activity, I am trying to figure out the simplest way to launch the dialog. Here is what I have tried:

public class SurveyView : MvxActivity
{
    public void ShowContainerDialog()
    {
        ContainerDialogViewModel vm = new ViewModels.ContainerDialogViewModel();
        vm.Init("Test Name");
        var dialogFragment = new ContainerDialog()
        {
            DataContext = vm
        };
        dialogFragment.Show(FragmentManager, "Containers");
    }
}

I'm pretty sure my method of creating the view model is unorthodox, but I don't know another way to do it. The biggest issue is that FragmentManager is cast to the wrong version. Show is looking for an Android.Support.V4.App.FragmentManager and the FragmentManager that is exposed is an Android.App.FragmentManager. I tried changing the MvxActivity to an MvxFragmentActivity, but this didn't seem to help. Can someone point me in the right direction?

Jim Wilcox
  • 1,236
  • 10
  • 30
  • A new presenter with support for Dialogs is planned for 5.1.0 – Martijn00 Jul 06 '17 at 07:49
  • @Martijn00 Is there a way to get it to work now? Like with a custom presenter or something like that? I have searched high and low for a working example of an MvxDialogFragment and haven't been able to find one. – Jim Wilcox Jul 06 '17 at 13:35
  • I'm working on this: https://github.com/MvvmCross/MvvmCross/issues/1934 – Martijn00 Jul 06 '17 at 14:11
  • @Martijn00 Thanks bro. I looked at the link and most of that is probably beyond my ability, but I might be able to test some of it if that would help. If there is anything I can contribute, please let me know. – Jim Wilcox Jul 06 '17 at 17:41
  • @Martijn00 I have installed version 5.4. Is there a way to do this yet? Can you point me to an example? – Jim Wilcox Nov 06 '17 at 21:49
  • It's all here now: https://github.com/MvvmCross/MvvmCross/tree/develop/TestProjects/Playground – Martijn00 Nov 07 '17 at 10:47

2 Answers2

6

MvvmCross didn't really support this when I was trying to do it, but I came across another instance where I needed this and alas, the functionality is there. Thanks to @Martijn00 for pointing me at the solution. This will be very basic, but I think it might help someone.

My Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
  <TextView
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      style="@style/TableHeaderTextView"
      android:text="Work Date"/>
  <MvxDatePicker
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20dp"
    local:MvxBind="Value WorkDate" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Close"
        local:MvxBind="Click CloseCommand" />
</LinearLayout>

My ViewModel:

public class HoursDateDialogViewModel : MvxViewModel<EstimateHours>
{
    private readonly IMvxNavigationService _navigationService;

    public HoursDateDialogViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;

        CloseCommand = new MvxAsyncCommand(async () => await _navigationService.Close(this));
    }

    public override System.Threading.Tasks.Task Initialize()
    {
        return base.Initialize();
    }

    public override void Prepare(EstimateHours parm)
    {
        base.Prepare();
        Hours = parm;
    }

    public IMvxAsyncCommand CloseCommand { get; private set; }

    private EstimateHours _Hours;
    public EstimateHours Hours
    {
        get
        {
            return _Hours;
                }
        set
        {
            _Hours = value;
            RaisePropertyChanged(() => Hours);
            RaisePropertyChanged(() => WorkDate);
        }
    }

    public DateTime WorkDate
    {
        get
        {
            return Hours.StartTime ?? DateTime.Today;
        }
        set
        {
            DateTime s = Hours.StartTime ?? DateTime.Today;
            DateTime d = new DateTime(value.Year, value.Month, value.Day, s.Hour, s.Minute, s.Second);
            Hours.StartTime = d;
            DateTime e = Hours.EndTime ?? DateTime.Today;
            d = new DateTime(value.Year, value.Month, value.Day, e.Hour, e.Minute, e.Second);
            Hours.EndTime = d;
            RaisePropertyChanged(() => WorkDate);
        }
    }

}

My View:

[MvxDialogFragmentPresentation]
[Register(nameof(HoursDateDialogView))]
public class HoursDateDialogView : MvxDialogFragment<HoursDateDialogViewModel>
{
    public HoursDateDialogView()
    {
    }

    protected HoursDateDialogView(IntPtr javaReference, JniHandleOwnership transfer)
        : base(javaReference, transfer)
    {
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        var ignore = base.OnCreateView(inflater, container, savedInstanceState);

        var view = this.BindingInflate(Resource.Layout.HoursDateDialogView, null);

        return view;
    }
}

That's all there is to it. I am able to pass a parameter object and bind part of the object to an MvxDatePicker. In order to show this dialog, first in your Setup.cs, you need :

    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {
        return new MvxAppCompatViewPresenter(AndroidViewAssemblies);
    }

In your viewmodel from which you will open the dialog, you need a constructor containing:

    private readonly IMvxNavigationService _navigationService;

    public LocalHourlyViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;
    }

This injects the navigation service so you can work with it. And finally, all you have to do to open the dialog is:

async () => await _navigationService.Navigate<HoursDateDialogViewModel, EstimateHours>(Item);

I'm not even sure you have to await the call, but I was following the example. You can see more examples at the link @Martijn00 provided:

https://github.com/MvvmCross/MvvmCross/tree/develop/TestProjects/Playground

Cheers!

Jim Wilcox
  • 1,236
  • 10
  • 30
  • +1 Also the activity that hosts MvxDialogFragment has to be MvxFragmentActivity. I know it was mentioned in other posts here but just for completeness of this answer. – Eva Lan Apr 15 '19 at 07:35
  • @EvaLan Just for the record, the hosting Activity can also be an MvxAppCompatActivity. This is what I generally use. Cheers :) – Jim Wilcox Apr 15 '19 at 13:04
0

I tried changing the MvxActivity to an MvxFragmentActivity

This was the correct first step. Then instead of passing in FragmentManager, pass in SupportFragmentManager.

If you are not familiar with Support Libraries, You can read more about what they are and how to use them with Xamarin here

pnavk
  • 4,132
  • 1
  • 16
  • 38
  • Your suggestions made it compile correctly and run, but when the dialog was shown, it was blank. It is inflating the View so I'm not sure what to do next. – Jim Wilcox Jul 07 '17 at 15:27
  • 1
    @JimWilcox - Instead of using OnCreateDialog, override OnCreateView instead and inflate your layout there. You can get rid of OnCreateDialog. Check out the comments in this code block for more info: https://stackoverflow.com/a/19302991/2754727 – pnavk Jul 07 '17 at 16:23