我是Xamarin cross-platform
的新手,虽然我确实对WPF
和MVVM
有过一些经验,但我仍然无法使用{{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
。
答案 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
});