Search code examples
c#wpfxamlmvvmcanexecute

How to use the CanExecute Method from ICommand on WPF


How does one use the CanExecute Method from the ICommand interface?


In my example i have a SaveCommand which i only what to be enable when the object is saveable. The XAML Code of my Savebutton looks like this:

<Button Content="Save" Command="{Binding SaveCommand, Mode=TwoWay}" />

This is the code of my save class:

class Save : ICommand
{
    public MainWindowViewModel viewModel { get; set; }

    public Save(MainWindowViewModel viewModel)
    {
        this.viewModel = viewModel;
    }

    public bool CanExecute(object parameter)
    {

        if (viewModel.IsSaveable == false)
            return false;
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        viewModel.Save();
    }
}

The save property in the ViewModel looks like this:

    public ICommand SaveCommand
    {
        get
        {
            saveCommand = new Save(this);
            return saveCommand;
        }
        set
        {
            saveCommand = value;
        }
    }

This construct didn't work. The button does not enable its self when isSaveable is true.


Solution

  • Instead of defining your own implementation of ICommand, use a RelayCommand.

    In the below sample code, the save Button is enabled when the user types something in the TextBox.

    XAML:

    <Window x:Class="RelayCommandDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel HorizontalAlignment="Center">
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Margin="5" Width="120"/>
            <Button Content="Save" Command="{Binding SaveCommand}" Margin="3"/>
        </StackPanel>
    </Window>
    

    Code behind:

    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace RelayCommandDemo
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                DataContext = new VM();
            }
        }
        public class VM
        {
            public String Name { get; set; }
    
            private ICommand _SaveCommand;
    
            public ICommand SaveCommand
            {
                get { return _SaveCommand; }
            }
    
            public VM()
            {
                _SaveCommand = new RelayCommand(SaveCommand_Execute, SaveCommand_CanExecute);
            }
    
            public void SaveCommand_Execute()
            {
                MessageBox.Show("Save Called");
            }
    
            public bool SaveCommand_CanExecute()
            {
                if (string.IsNullOrEmpty(Name))
                    return false;
                else
                    return true;
            }
        }
    
        public class RelayCommand : ICommand
        {
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
            private Action methodToExecute;
            private Func<bool> canExecuteEvaluator;
            public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
            {
                this.methodToExecute = methodToExecute;
                this.canExecuteEvaluator = canExecuteEvaluator;
            }
            public RelayCommand(Action methodToExecute)
                : this(methodToExecute, null)
            {
            }
            public bool CanExecute(object parameter)
            {
                if (this.canExecuteEvaluator == null)
                {
                    return true;
                }
                else
                {
                    bool result = this.canExecuteEvaluator.Invoke();
                    return result;
                }
            }
            public void Execute(object parameter)
            {
                this.methodToExecute.Invoke();
            }
        }
    }