2

I am new to WPF and c# in general. I was reading about the Command Design Pattern and was looking forward to implement it on my new application so that it could have do and undo functionality. Then i realized that WPF already comes with a ICommand Interface and that de xml buttons can implement it. Said interface have this methods:

public bool CanExecute(object parameter)
{
}

private void OnCanExecuteChanged()
{
}

public void Execute(object parameter)
{
}

So, should i add the undo funcionality to this already build in ICommand Interface by having some other interface inherit from it and add the undo method?

is this interface ment only for buttons? I mean, i would like to create many other commands that are not necesarilly connected to a xnml button

thanks in advance!

Darthmw
  • 51
  • 5

4 Answers4

1

First of all, the commands are part of the MVVM pattern and you should first read about it.

Interfaces in C # do not provide any functionality, they only describe how the class that inherits this interface should work. If you want the class to do something, you should not leave these methods empty.

Commands in WPF represent a kind of framework to which logic will be transmitted later. The most logical use of commands is to bind them to buttons.

ICommand implementation example:

public class RelayCommand : ICommand
{
    private readonly Action<object>     execute;
    private readonly Func<object, bool> canExecute;

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

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        this.execute    = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }
}

Command using example:

 public static RelayCommand NavigateToSignInPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new LoginForm()));

    public static RelayCommand NavigateToSignUpPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new RegistrationForm()));

    public static RelayCommand NavigateToStartPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new StartPage()));

    public static RelayCommand NavigateBack => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateBack(),
        actionPossibilityParameter => Application.Instance.Navigation.BackNavigationPossible);

Command binding example: In View (xaml):

<Button x:Name="CancelButton"
            Content="Cancel"
            Command="{Binding CancelCommand}"
            Grid.Row="2"
            IsCancel="True"
            HorizontalAlignment="Left"
            Margin="44,0,0,0"
            Width="118" Height="23"
            VerticalAlignment="Center" />

In ViewModel:

        public RelayCommand CancelCommand => NavigationCommands.NavigateBack;
0
  1. the CanExecute will lead you to whether do Command or not, for Command implement, you can see here.
  2. You Commmand binding to Button is binding to click not Button control. So all "Command" binding, not limit to click, also check, drop, focus, etc works
Sam Xia
  • 171
  • 11
0

I think you're confusing to differnt things right here. The ICommand Interface is something uses to Bind UI Events to code used in design patterns like MVVM. The Command Design Pattern you're trying to implement is a state architecture for undoing actions like a button press.

Tom Stein
  • 345
  • 2
  • 15
  • So, i would be better off creating my own ICustomCommand interface to implement the do-undo funcionality. Right? – Darthmw Mar 11 '19 at 19:55
  • Yeah, that would be something to do additonally if you choose to use MVVM which I think you don't because its a somewhat complex design pattern. What you want to do is pretty well described here: [how to use command pattern for undo](https://matt.berther.io/2004/09/16/using-the-command-pattern-for-undo-functionality/) – Tom Stein Mar 11 '19 at 19:57
0

Many of the answers highlight a useful implementation of the ICommand interface using delegates. You could even go further by binding to model changes as shown below or arbitrarily filter if you so choose. This can be useful to re-evaluate whether or not a command should be able to fire based upon model state as this is directly tied to the "Enabled" state of a button.

public class ObservableCommand<T> : ICommand where T : System.ComponentModel.INotifyPropertyChanged
{
    Predicate<object> _predicate;
    Action<object> _execute;
    public ObservableCommand(T model, Action<object> execute, Predicate<object> predicate)
    {
        model.PropertyChanged += ModelChanged;
        _execute = execute;
        _predicate = predicate;
    }

    public event EventHandler CanExecuteChanged;

    private void ModelChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

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

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

Regarding your question for undo operations. You certainly can use a command to invoke this but keeping track of the state of your objects is the more tricky part. You can use the memento design pattern and bind your command to the restoring state functionality. This is an oversimplification but has been the core of implementations I've done in the past.

public class Memento<T>
{
    public Memento(T startState)
    {
        this.State = startState;
        this.OriginalState = startState;
    }

    public T State { get; set; }

    public T OriginalState { get; }

    public void RestorOriginalState()
    {
        State = OriginalState;
    }
}
fanuc_bob
  • 857
  • 1
  • 7
  • 20