2015-08-04 2 views
3

Я очень новый для Xamarin cross-platform и в то время как я имел некоторый опыт работы с WPF и MVVM я все еще имею проблему понимания параметризированного RelayCommand вызова с использованием ICommand реализации ниже. Может кто-нибудь объяснить, как правильно передать и получить CommandParameter от моей точки зрения в моей связанной RelayCommand как это кажется тихим отличается от обычной WPF версии RelayCommand:параметра RelayCommand переходящий в Xamarin

/// <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.

ответ

5

Я считаю, что вы получаете события и команды запутались. Некоторые различия между ними заключаются в том, что вам необходимо подписаться на события и события. Команды могут быть вызваны кем угодно, а также могут быть заблокированы.

Чтобы заставить вас работать правильно, вы должны изменить свой код, чтобы позволить вашему RelayCommand принять действие с помощью параметра. Этот параметр определит Тип параметра. Я бы использовал что-то вроде MVVMLight, которое содержит Generic RelayCommand, так что вам не нужно писать самостоятельно. Как только это будет сделано, вы сможете изменить свой код, чтобы выглядеть так.

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

Я написал небольшую blog post, который содержит полный рабочий проект, если вы хотите увидеть рабочий пример.

0

реле или делегат команды для Xamarin

Вот как я достигну, я надеюсь, что это будет полезно для кого-то

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 
}); 
Смежные вопросы