Dave
Dave

Reputation: 1925

How to bind button to Cmd with parameter in Android + MVVMCross

I have a very simple application that rely on MVVMCross + Xamarin Android.

I have been able to create a WP8 application LoginView (Username + Password + Submit Button) that bind to a Cmd with parameter(which will be my password) in the ViewModel . Now I try to do the same with Android . How to express the CommandParameter(which is another field of the view) in the axml file for my LoginView?

    public class LoginViewModel : MvxViewModel
{
    private readonly ILoginService _loginService;

    public LoginViewModel(ILoginService loginService)
    {
        _loginService = loginService;
    }

    private string _username;
    public string Username
    { 
        get { return _username; }
        set { _username = value; RaisePropertyChanged(() => Username); }
    }

    private string _error;
    public string Error {
        get { return _error; }
        set { _error = value; RaisePropertyChanged(() => Error); }
    }

    #region LoginCmd
    private MvxCommand<string> _loginCmd;
    public ICommand LoginCmd
    {
        get
        {
            _loginCmd = _loginCmd ?? new MvxCommand<string>(DoLoginCmd);
            return _loginCmd;
        }
    }

    private void DoLoginCmd(string password)
    {
        try
        {
            _loginService.Login(Username, password);
            ShowViewModel<ProjectsListViewModel>();
        }
        catch (SecurityException ex)
        {
            Error = ex.Message;
        }
    }
    #endregion
}

Upvotes: 2

Views: 2668

Answers (1)

Stuart
Stuart

Reputation: 66882

For general commandparameter binding see Using MvxCommand With CommandParameter binding

For binding to a value within the View, my general answer is don't

MvvmCross doesn't support ElementName or RelativeSource type binding source.

Instead all bindings are to the ViewModel/DataContext

For your app example, you could easily bind the Password to a property in your ViewModel - just like you do with UserName


Update after comments discussion.

If Password is a special case because of Xaml security concerns, then some options you could try are:

  • you could work around those security concerns using AttachedProperties - see links like http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html for details

  • you could bind the Password property on Android and iOS and then use the Tibet binding syntax to bind the Click event with a ViewModel bound CommandParameter - something like Click CommandParameter(LoginCmd, Password)

  • you could use ViewModel based-logic to use either the parameter-passed-in Password or (when null) the ViewModel Password property (password = password ?? Password;)

  • you could use code-behind or custom control binding tricks to make the command parameter work... e.g. you could:

    • inherit a LoginButton from Button
    • add a SetPasswordEditText(EditText text) method to LoginButton
    • add a PasswordClick ICommand property to LoginButton and cause it to fire
    • use a little code-behind to wire up the UI to provide the Password at Command-time
    • this might look like

.

 public class LoginButton : Button
 {
    public LoginButton(Context c, IAttributeSet a) : base(c,a) {
       this.Click += (s,e) => {
         if (LoginClick == null) return;
         if (PasswordEditText == null) return;
         if (LoginClick.CanExecute(PasswordEditText.Text))
           LoginClick.Execute(PasswordEditText.Text);
       }
    }

    public ICommand LoginClick {get;set;}
    public EditText PasswordEditText {get;set;}
 }

 // codebehind in OnCreate as:
 var l = FindViewById<LoginButton>(Resource.Id.the_login_button);
 var p = FindViewById<EditText>(Resource.Id.the_password_box);

 l.PasswordEditText = p;

 // Axml is:
 <LoginButton 
    local:MvxBind="LoginClick LoginCmd"
    android:... etc />

Upvotes: 4

Related Questions