Click here to Skip to main content
15,881,600 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
How to pass & read command parameter in ViewModel

C#
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <RadioButton x:Name="rbOTP" Content="Use Login OTP" Tag="1"  Padding="12,8,12,8" GroupName="OTPOption" Style="{StaticResource StashOTPOption}" 
                             ToolTip="Recieve OTP via email" IsChecked="True" Command="{Binding OTPOptionCommand}" CommandParameter="{Binding ElementName=rbOTP, Path=Tag}"/>
                
                <RadioButton x:Name="rbLoginCode" Content="Use Login Code" Tag="2" Padding="12,8,12,8" GroupName="OTPOption" Style="{StaticResource StashOTPOption}" 
                             ToolTip="Use pre-generated login codes" Command="{Binding OTPOptionCommand}" CommandParameter="{Binding ElementName=rbLoginCode, Path=Tag}"/>
                
                <RadioButton x:Name="rbPin" Content="Use Secret Pin" Tag="3" Padding="12,8,12,8" GroupName="OTPOption" Style="{StaticResource StashOTPOption}"
                             ToolTip="Use secret pin" Command="{Binding OTPOptionCommand}" CommandParameter="{Binding ElementName=rbPin, Path=Tag}"/>
            </StackPanel>

C#
//OTP Option
private ICommand _otpOptionCommand;

public ICommand OTPOptionCommand
{
  get 
  { 
   if (_otpOptionCommand == null)
   {
     _otpOptionCommand = new RelayCommand(SetOtpOption, CanSetOtpOption);
   }
   return _otpOptionCommand;
  }
}

private bool CanSetOtpOption(object obj)
{
  return true;
}

private void SetOtpOption(object obj)
{
  //Set the OTPOption value to the checked radio button tag value
}


What I have tried:

I tried binding the property to each radio button IsChecked and used a boolean to int converter
Posted
Updated 18-Feb-23 17:24pm
Comments
George Swan 19-Feb-23 2:55am    
Your code looks ok to me. The type passed to the SetOtpOption(object obj) method is a string. You need to cast that to an int like this: int tag = int.Parse((string)obj);

1 solution

Use the MVVM ToolKit[^]. One of the thinks that they have is a RelayCommand[^] that will make life simple for you.

But if you want to roll-your-own, here is one that I use:
C#
public class RelayCommand : RelayCommand<object>
{
    public RelayCommand(Action<object> execute)
        : base(execute) { /* skip */ }

    public RelayCommand(Action<object> execute, Predicate<object>? canExecute)
        : base(execute, canExecute) { /* skip */ }
}

public class RelayCommand<TValue> : ICommand
{
    #region Fields

    private readonly Action<TValue> _execute;
    private readonly Predicate<TValue>? _canExecute;
    private EventHandler? _internalCanExecuteChanged;

    #endregion

    #region Constructors

    public RelayCommand(Action<TValue> execute)
        : this(execute, null) { /* skip */ }

    public RelayCommand(Action<TValue> execute, Predicate<TValue>? canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    #endregion

    #region ICommand Members

    public event EventHandler? CanExecuteChanged
    {
        add
        {
            _internalCanExecuteChanged += value;
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            _internalCanExecuteChanged -= value;
            CommandManager.RequerySuggested -= value;
        }
    }

    // ref: https://stackoverflow.com/a/8475103/327541
    // This method can be used to raise the CanExecuteChanged handler.
    // This will force WPF to re-query the status of this command directly.
    public void RaiseCanExecuteChanged()
    {
        if (_canExecute != null)
            OnCanExecuteChanged();
    }

    public void Execute(object? parameter)
        => _execute((parameter is null ? default : (TValue)parameter)!);

    public bool CanExecute(object? parameter)
        => _canExecute == null || (parameter is null ?  _canExecute(default!) : _canExecute((TValue)parameter));

    protected virtual void OnCanExecuteChanged()
    {
        EventHandler? eCanExecuteChanged = _internalCanExecuteChanged;
        if (eCanExecuteChanged == null)
            return;

        eCanExecuteChanged(this, EventArgs.Empty);
    }

    #endregion
}

To use...

1. declare a property:
C#
public RelayCommand MyCommand { get; set; }

2. Initialise in the constructor:
C#
MyCommand = new RelayCommand(execute: MyMethod, canExecute: _ => true);

3. The Method that executes:
C#
private void MyMethod(object obj)
{
    // do work here...
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900