Darthmw
Darthmw

Reputation: 51

C# WPF built in ICommand Interface and the Command Design Patttern

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!

Upvotes: 2

Views: 3209

Answers (4)

Nick__Dudas
Nick__Dudas

Reputation: 886

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;
    }
}

Upvotes: 0

Anton Kosenko
Anton Kosenko

Reputation: 65

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;

Upvotes: 1

Tom Stein
Tom Stein

Reputation: 365

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.

Upvotes: 0

Sam Xia
Sam Xia

Reputation: 181

  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

Upvotes: 0

Related Questions