Question

I am using MvvmCross, but this may be general command binding.

When user click a button, the application require an extra input data before proceed to what I want to do in the actual command. The problem that I cannot call an UI action in middle of ViewModel, so just binding MvxCommand (or any ICommand) would not work.

One may ask why: 1) I don't put an input on the UI and user can enter data before click button -> I don't have space. 2) Make default data, and let user change it later -> This my first though, but user tend to forget to change it later!!

So can someone come up with a solution? The only thing I can think of is forgetting command binding, and have code behind pop the ui for extra data, then call a method in view model!

Thanks

Was it helpful?

Solution

There are several ways to do this.

My personal preferred way is to use an "Interaction Request" - something that I learnt from the Prism framework from Microsoft patterns and practices.

In Mvx, you can do this using an IMvxInteraction property on your ViewModel. An example of this is shown in https://github.com/slodge/BindingTalk/blob/master/BindingTalk.Core/ViewModels/QuestionViewModel.cs

Each time an interaction is requested, the ViewModel provides an object to the View - in this case a YesNoQuestion:

public class YesNoQuestion
{
    public Action YesAction { get; set; }
    public Action NoAction { get; set; }
    public string QuestionText { get; set; }

    public YesNoQuestion()
    {
        YesAction = () => { };
        NoAction = () => { };
    }
}

The ViewModel exposes the requester using an IMvxInteraction<TQuestion> property:

public class QuestionViewModel
    : MvxViewModel
{
    private MvxInteraction<YesNoQuestion> _confirm = new MvxInteraction<YesNoQuestion>();
    public IMvxInteraction<YesNoQuestion> Confirm
    {
        get { return _confirm; }
    }

    public IMvxCommand GoCommand
    {
        get
        {
            return new MvxCommand(() =>
                {
                    var question = new YesNoQuestion()
                        {
                            QuestionText = "Close me now?",
                            YesAction = () => Close(this),
                        };
                    _confirm.Raise(question);
                });
        }
    }
}

The view on each platform can then bind and subscribe to the interaction request property. This is a little fiddly - because it uses weak references to prevent memory leaks - especially on iOS, but also possible on other platforms too.

Some example Droid code for this is in:

Sorry for the confusing ConfirmationView and QuestionView names here - the first is an Android View, the second is an Mvvm View and an Android Activity.

Also, please note that when implementing Dialogs in Android, then you need to be careful about screen rotation - as Android's Activity lifecycle can very much confuse things here - easiest mecahnism (I find) is to just handle screen rotation yourself rather than allowing Android to handle it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top