RelayCommand parameter passing in Xamarin

I am very new to Xamarin cross-platform

, and although I have had some experience with WPF

and MVVM

, I am still getting my head around parameterized calling RelayCommand

using the implementation ICommand

below. Can someone please explain how to properly pass and receive CommandParameter

from my view to my linked RelayCommand

, as this seems to be quiet, different from the normal version WPF

RelayCommand

:

    /// <summary>
    /// A command whose sole purpose is to relay its functionality 
    /// to other objects by invoking delegates. 
    /// The default return value for the CanExecute method is 'true'.
    /// <see cref="RaiseCanExecuteChanged"/> needs to be called whenever
    /// <see cref="CanExecute"/> is expected to return a different value.
    /// </summary>
    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        /// <summary>
        /// Raised when RaiseCanExecuteChanged is called.
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        /// <summary>
        /// Determines whether this <see cref="RelayCommand"/> can execute in its current state.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command. If the command does not require data to be passed, this object can be set to null.
        /// </param>
        /// <returns>true if this command can be executed; otherwise, false.</returns>
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        /// <summary>
        /// Executes the <see cref="RelayCommand"/> on the current command target.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command. If the command does not require data to be passed, this object can be set to null.
        /// </param>
        public void Execute(object parameter)
        {
            _execute();
        }

        /// <summary>
        /// Method used to raise the <see cref="CanExecuteChanged"/> event
        /// to indicate that the return value of the <see cref="CanExecute"/>
        /// method has changed.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

      

Earlier in WPF I had something like:

<Command="{Binding OpenMenuItemCommand}"
            CommandParameter="{Binding SelectedItem}"/>

      

and on the side ViewModel

:

  OpenMenuItemCommand = new RelayCommand(OpenMenuItem);
  ...
  public void OpenMenuItem(object sender, ItemTappedEventArgs args)
  {
  }

      

So my parameter will go through args

.

+3


source to share


2 answers


I believe you are confusing events and commands. Some of the differences between the two are that you need to subscribe to events and events. Teams can be called by anyone and can also be blocked.

So, so that you can work properly, you must change your code to allow your RelayCommand to take a parameter action. This parameter will determine the Type of the parameter. I would use something like MVVMLight that contains a Generic RelayCommand so you don't have to write your own. Once this is done, you can modify your code to look like this.



 OpenMenuItemCommand = new RelayCommand<MenuItem>(OpenMenuItem);
  ...
  public void OpenMenuItem(MenuItem item)
  {
  }

      

I wrote a small blog post containing a complete working draft if you want to see a working example.

+5


source


Relay or delegate command for Xamarin

The way I achieve this, hope this is helpful for someone

public class DelegateCommand : ICommand
{
    /// <summary>
    /// The _execute
    /// </summary>
    private readonly Action _execute;

    /// <summary>
    /// The _can execute
    /// </summary>
    private readonly Func<bool> _canExecute;

    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    /// <param name="canExecute">The can execute.</param>
    /// <exception cref="System.ArgumentNullException">execute</exception>
    public DelegateCommand(Action execute, Func<bool> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException("execute");

        if (canExecute != null)
        {
            this._canExecute = canExecute;
        }
    }

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class that
    /// can always execute.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
    public DelegateCommand(Action execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Occurs when changes occur that affect whether the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged;


    /// <summary>
    /// Raises the can execute changed.
    /// </summary>
    public void RaiseCanExecuteChanged()
    {

        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    /// <returns>true if this command can be executed; otherwise, false.</returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute.Invoke();
    }

    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public virtual void Execute(object parameter)
    {
        if (CanExecute(parameter))
        {
            _execute.Invoke();
        }
    }
}

/// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
/// <typeparam name="T">Type of the parameter passed to the delegates</typeparam>
public class DelegateCommand<T> : ICommand
{
    /// <summary>
    /// The execute
    /// </summary>
    private readonly Action<T> _execute;

    /// <summary>
    /// The can execute
    /// </summary>
    private readonly Predicate<T> _canExecute;

    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand{T}" /> class.
    /// </summary>
    /// <param name="execute">The execute action.</param>
    /// <exception cref="System.ArgumentNullException">execute</exception>
    public DelegateCommand(Action<T> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand{T}" /> class.
    /// </summary>
    /// <param name="execute">The execute.</param>
    /// <param name="canExecute">The can execute predicate.</param>
    /// <exception cref="System.ArgumentNullException">execute</exception>
    public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException("execute");

        if (canExecute != null)
        {
            _canExecute = canExecute;
        }
    }

    /// <summary>
    /// Occurs when changes occur that affect whether the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged;

    /// <summary>
    /// Raise <see cref="RelayCommand{T}.CanExecuteChanged" /> event.
    /// </summary>
    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    /// <summary>
    /// Determines whether this instance can execute the specified parameter.
    /// </summary>
    /// <param name="parameter">The parameter.</param>
    /// <returns><c>true</c> if this instance can execute the specified parameter; otherwise, <c>false</c>.</returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute.Invoke((T)parameter);
    }

    /// <summary>
    /// Executes the specified parameter.
    /// </summary>
    /// <param name="parameter">The parameter.</param>
    public virtual void Execute(object parameter)
    {
        if (CanExecute(parameter))
        {
            _execute((T)parameter);
        }
    }
}

      

in your view



<Button Text="Login Command" Command="{Binding LoginCommand}" 
            CommandParameter="12345" />

      

in your view model

public ICommand LoginCommand { get; }
LoginCommand = new DelegateCommand<object>(
x =>
{
     // x will be containing 12345
     // your code 
});

      

0


source







All Articles