20

I have a simple button that uses a command when executed, this is all working fine but I would like to pass a text parameter when the button is clicked.

I think my XAML is ok, but I'm unsure how to edit my RelayCommand class to receive a parameter:

<Button x:Name="AddCommand" Content="Add" 
    Command="{Binding AddPhoneCommand}"
    CommandParameter="{Binding Text, ElementName=txtAddPhone}" />
public class RelayCommand : ICommand
{
    private readonly Action _handler;
    private bool _isEnabled;

    public RelayCommand(Action handler)
    {
        _handler = handler;
    }

    public bool IsEnabled
    {
        get { return _isEnabled; }
        set
        {
            if (value != _isEnabled)
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                {
                    CanExecuteChanged(this, EventArgs.Empty);
                }
            }
        }
    }

    public bool CanExecute(object parameter)
    {
        return IsEnabled;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _handler();
    }
}
Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
Michael Harper
  • 1,531
  • 2
  • 25
  • 42

3 Answers3

13

Change Action to Action<T> so that it takes a parameter (probably just Action<object> is easiest).

private readonly Action<object> _handler;

And then simply pass it the parameter:

public void Execute(object parameter)
{
    _handler(parameter);
}
McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • Thanks that works great! I'm not that new to WPF but I am new to MVVM so commands are a new concept; but I can already see how they would help unit tests. So adding isn't saying Action of type object but rather this delegate takes an object parameter? – Michael Harper Oct 28 '12 at 20:50
  • @MichaelHarper yes, exactly, a delegate that takes one object parameter. You can see they've defined multiple action types along those lines: http://msdn.microsoft.com/en-us/library/018hxwa8.aspx – McGarnagle Oct 28 '12 at 20:55
  • Thanks again, been a great help :D – Michael Harper Oct 28 '12 at 21:04
6

You could just do

public ICommand AddPhoneCommand
{
    get
    {
        return new Command<string>((x) =>
        {
            if(x != null) { AddPhone(x); }
        };
    }
}

Then, of course have your AddPhone:

public void AddPhone(string x)
{
    //handle x
}
Jud
  • 1,324
  • 3
  • 24
  • 47
3

You can simply do this (no change to RelayCommand or ICommand required):

private RelayCommand _addPhoneCommand;
public RelayCommand AddPhoneCommand
{
    get
    {
        if (_addPhoneCommand == null)
        {
            _addPhoneCommand = new RelayCommand(
                (parameter) => AddPhone(parameter),
                (parameter) => IsValidPhone(parameter)
            );
        }
        return _addPhoneCommand;
    }
}

public void AddPhone(object parameter)
{
    var text = (string)parameter;
    ...
}

public void IsValidPhone(object parameter)
    var text = (string)parameter;
    ...
}
philu
  • 795
  • 1
  • 8
  • 17