wpf Xamarin 中的 RelayCommand 参数传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31812035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RelayCommand parameter passing in Xamarin
提问by eYe
I am very new to Xamarin cross-platformand while I did have some experience with WPFand MVVMI am still having issue understanding parameterized RelayCommandinvocation using ICommandimplementation below. Can someone explain how to properly pass and receive a CommandParameterfrom my View into my bound RelayCommandas this seems quiet different from a normal WPFversion of RelayCommand:
我是很新的Xamarin cross-platform,虽然我也有一定的经验WPF和MVVM我仍然有问题,了解参数RelayCommand使用调用ICommand下面执行。有人可以解释如何CommandParameter从我的视图中正确地传递和接收 a到我的边界,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);
}
}
}
Before in WPF I used to have something like:
在 WPF 之前,我曾经有过类似的事情:
<Command="{Binding OpenMenuItemCommand}"
CommandParameter="{Binding SelectedItem}"/>
and on ViewModelside:
和ViewModel面:
OpenMenuItemCommand = new RelayCommand(OpenMenuItem);
...
public void OpenMenuItem(object sender, ItemTappedEventArgs args)
{
}
So my parameter would come through args.
所以我的参数会通过args.
回答by Andres Castro
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 MVVMLightwhich contains a Generic RelayCommandso 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.
因此,为了让示例正常工作,您应该修改代码以允许 RelayCommand 使用参数执行操作。此参数将定义参数的类型。我会使用像MVVMLight这样的东西,它包含一个通用的 RelayCommand,这样你就不必自己写了。完成后,您应该能够将代码更改为如下所示。
OpenMenuItemCommand = new RelayCommand<MenuItem>(OpenMenuItem);
...
public void OpenMenuItem(MenuItem item)
{
}
I wrote a small blog postthat contains a full working project if you want to see a working example.
回答by dnxit
Relay or Delegate Command for Xamarin
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
});

