MvvMCross bind command with parameter (in C# code)
Asked Answered
T

3

5

How can I bind a command to a button in code in MvvMCross (Xamarin.iOS) with specifying a command parameter?

// command definition
public MvxCommand SaveDealerDataCommand
{
    get { return new MvxCommand<bool>(DoSaveDealerDataAction); }
}

public void DoSaveDealerDataAction(bool show)
{
    //...
}

// binding
bindingset.Bind(saveButton).To(vm => vm.SaveDealerDataCommand); 

Where can I specify the parameter (true/false) that will be passed to the command?

Telephoto answered 5/7, 2013 at 15:51 Comment(0)
T
9

Android and iOS buttons don't have CommandParameter properties in the same way that Windows ones do.

However, MvvmCross did recently introduce a way to introduce CommandParameter bindings via Value Converters - see http://slodge.blogspot.co.uk/2013/06/commandparameter-binding.html

This binding should work as:

 bindingset
    .Bind(saveButton)
    .To(vm => vm.SaveDealerDataCommand)
    .WithConversion("CommandParameter", true);     

or:

 bindingset
    .Bind(saveButton)
    .To(vm => vm.SaveDealerDataCommand)
    .WithConversion(new MvxCommandParameterValueConverter(), true);     

Note that this CommandParameter binding isn't completely in the 3.0.8.1 package which is the stable nuget release, so to make this work you may need to either:

  1. Add this manual value converter registration in your Setup.cs

    protected override void FillValueConverters(IMvxValueConverterRegistry registry)
    {
        base.FillValueConverters(registry);
        registry.AddOrOverwrite(
            "CommandParameter", 
            new Cirrious.MvvmCross.Binding.MvxCommandParameterValueConverter()
        );
    }
    
  2. Or use one of the beta nuget packages uploaded since 3.0.8.1 (set nuget to include prereleases to see these packages).

  3. Or build the source yourself

Translative answered 5/7, 2013 at 17:8 Comment(1)
Is there any new update to this answer? I'd like to have a dynamic command parameter in iOS for my UIButton. For example, when you click the button, it would call my command with the current Text in one of my UITextField controls...and all hooked up with .Bind.Pavlish
C
1

To achieve your dynamic command parameter using the text in one of your UITextField controls, you could bind the text in that UITextField to a string property on you ViewModel and the code that runs in your button's bound command would be able to access the value via that property when it executes.

In your ViewController, something like:

UITextField textField = new UTextField();
textField.Frame = new RectangleF(0,0,120,30);
Add(textField);
UIButton button = new UIButton();
button.Frame = new RectangleF(70,40,50,30);
button.SetTitle("Click Me");
Add(button);

var bindingSet = this.CreateBindingSet<MyView, MyViewModel>();
bindingSet.Bind(textField).To(vm => vm.StringProperty);
bindingSet.Bind(button).To(vm => vm.ClickCommand);
bindingSet.Apply();

Then, in your ViewModel:

private string _stringProperty = string.Empty;
public string StringProperty
{
    get { return _stringProperty; }
    set
    {
        _stringProperty = value;
        RaisePropertyChanged(() => StringProperty);
    }
}
public ICommand ClickCommand
{
    get
    {
        return new MvxCommand(HandleClick);
    }
}

public void HandleClick()
{
    //Code that accesses StringProperty (which contains the UITextField's value)
}
Cannery answered 23/4, 2014 at 13:46 Comment(2)
Hi, sorry, but that doesn't fit my problem (from 1 year ago). The question targeted command parameters.Hemminger
Sorry, I was attempting to answer the question posed by Michael in the Comment below your orginal post.Cannery
P
0

To pass a dynamic command parameters to the command in the view model you could create a new class e.g. like this DynamicCommandParameterValueConverter:

    /// <summary>
    /// This class is inspired by MvvmCross MvxCommandParameterValueConverter,
    /// but because we need dynamic command parameters, we need to implement our own combined with a CustomMvxWrappingCommand.
    /// </summary>
    /// <typeparam name="T">The type of the 'selected item' for the command</typeparam>
    /// <typeparam name="TResult">The returned result that is used as input for the command.</typeparam>
    public class DynamicCommandParameterValueConverter<T, TResult> : MvxValueConverter<ICommand, ICommand>
    {
        private readonly Func<T, TResult> commandParameterExpression;

        public DynamicCommandParameterValueConverter(Func<T, TResult> commandParameterExpression)
        {
            this.commandParameterExpression = commandParameterExpression;
        }

        protected override ICommand Convert(ICommand value, Type targetType, object parameter, CultureInfo culture)
        {
            return new CustomMvxWrappingCommand<T, TResult>(value, commandParameterExpression);
        }
    }

The CustomMvxWrappingCommand takes a Func as argument, and is later invoked and passed into the commands CanExecute/Execute method. Here is a snippet of how part of that class could look like:

 public void Execute(object parameter)
        {
            if (wrapped == null)
            {
                return;
            }

            if (parameter != null)
            {
                Mvx.Warning("Non-null parameter overridden in MvxWrappingCommand");
            }

            wrapped.Execute(commandParameterOverride((T)parameter));
        }

You could modify the MvxWrappingCommand class from Mvx to implement the above example.

The use of it all:

            set.Bind(myControl).For(control => control.ItemClick).To(vm => vm.MyCommand).WithConversion(
            new DynamicCommandParameterValueConverter<MyModel, string>((MyModel item) =>
            {
              // Do custom logic before parsing the item..
            }));
Pangaro answered 4/8, 2015 at 13:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.