I am very new to Xamarin cross-platform
and while I did have some experience with WPF
and MVVM
I am still having issue understanding p
Relay or Delegate Command for Xamarin
That's how I achieve it, I hope it'll be 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
});
I believe you are getting events and commands confused. Some of the difference between the two are that you need to subscribe to events and events must occur. Commands can be called by anyone and also have the ability to be blocked.
So to get you example to work correctly you should modify your code to allow your RelayCommand to take an action with a parameter. This parameter will define the Type of the parameter. I would use something like MVVMLight which contains a Generic RelayCommand so that you don't have to write your own. Once that is done you should be able to change your code to look like this.
OpenMenuItemCommand = new RelayCommand<MenuItem>(OpenMenuItem);
...
public void OpenMenuItem(MenuItem item)
{
}
I wrote a small blog post that contains a full working project if you want to see a working example.