在Xamarin中传递的RelayCommand参数

时间:2015-08-04 14:28:31

标签: c# wpf mvvm xamarin

我是Xamarin cross-platform的新手,虽然我确实对WPFMVVM有过一些经验,但我仍然无法使用{{1}了解参数化RelayCommand调用的问题下面的实现。有人可以解释如何从我的视图中正确传递和接收ICommand到我的绑定CommandParameter,因为这似乎与RelayCommand 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);
            }
        }
    }

在WPF之前,我曾经有类似的东西:

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

并在ViewModel方面:

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

所以我的参数会通过args

2 个答案:

答案 0 :(得分:5)

我相信你会让事件和命令混乱。两者之间的一些区别是您需要订阅事件并且必须发生事件。命令可以被任何人调用,也可以被阻止。

因此,为了让您的示例正常工作,您应修改代码以允许RelayCommand使用参数执行操作。此参数将定义参数的类型。我会使用类似MVVMLight的内容,其中包含Generic RelayCommand,这样您就不必编写自己的内容。完成后,您应该能够将代码更改为这样。

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

如果你想看一个有效的例子,我写了一个包含完整工作项目的小blog post

答案 1 :(得分:1)

Xamarin的Relay或Delegate命令

这就是我实现它的方式,我希望它对某人有用

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);
        }
    }
}

在你的视图中

<Button Text="Login Command" Command="{Binding LoginCommand}" 
            CommandParameter="12345" />
在您的视图模型中

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