WPF RelayCommand with parameter

WPF RelayCommand with parameter
5 years, 1 month ago 0
Posted in: Programming

One of the things I frequently run across while coding in WPF is the need to pass a parameter to a bound command. Typically on the view model side, the command is handled by a Relay Command, but I wanted a bit more type safety than just having take any arbitrary object. So with a little modification, the Relay Command can be made into a generic and we’ll be able to gain all the nice type safety checks at compile time.

The source file is available for download and has been reproduced below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Windows.Input
{
    public class RelayCommand<T> : ICommand
    {
        #region Fields

        private readonly Action<T> _execute = null;
        private readonly Predicate<T> _canExecute = null;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action<T> execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Creates a new command with conditional execution.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute((T)parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }

        #endregion
    }
}

Using the parameterized Relay Command is straight forward. The only not so nice part is that commands that take in no parameters must take an object type which won’t be used. Here’s an example of the Relay Command with no parameters:

ViewModel

public ICommand NoParameterCommand
{
get
{
if (null == _noParameterCommand)
_noParameterCommand = new RelayCommand<object>(ExecuteNoParameterCommand);

return _noParameterCommand;
}
}

private void ExecuteNoParameterCommand(object notUsed)
{
}

View

<Button Command="{Binding Path=NoParameterCommand}"/>

While commands with no parameters are slightly more troublesome, commands with parameters are quite easy now:

ViewModel

public enum Fruit
{
    Apple,
    Banana,
    Cantaloupe,
}

private RelayCommand<Fruit> _fruitParameterCommand;
public ICommand FruitParameterCommand
{
    get
    {
        if (null == _fruitParameterCommand)
            _fruitParameterCommand = new RelayCommand<Fruit>(ExecuteFruitParameterCommand);

        return _fruitParameterCommand;
    }
}

private void ExecuteFruitParameterCommand(Fruit fruit)
{
}

View

<Button Command="{Binding Path=FruitParameterCommand}" CommandParameter="{x:Static local:Fruit.Banana}"/>

Remember to include the namespace reference local to the XAML file.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *