Skip to content

Commanding

Gennady Verdel edited this page Sep 20, 2021 · 2 revisions

The purpose of this project is to provide the most versatile and robust implementation of ICommand interface in .NET.

You will find here various examples of using the command, ranging from the simplest scenarios inside view models and to the most complex ones which involve visual tree analysis. Sit back and enjoy the ride!

Supported platforms


The package contains two parts: Core which supports .NETStandard 2.0 and Platform which contains platform-specific assemblies. The supported platforms include: .NET Framework 4.6+, .NET Core 3.1+, .NET 5.

Bootstrapping


The package contains platform-speficic means of command manager initialization. Use the following line inside the bootstrapper code:

bootstrapper.UseCommanding();

Basic usage


The most basic usage involves two main actors: View and ViewModel

ViewModel

private ICommand _testCommand;
public ICommand TestCommand 
{
    get 
    {
          return _testCommand ?? (_testCommand = ActionCommand.Do(SomeInternalHandling)); 
    }
}

View

<Button Command="{Binding TestCommand}" />

In this simplistic scenario we see clean separation between view and its view-model, lazy initialization of the command and small portion of ActionCommand API. More to come!

Conditions


Lots of times you would want the presentation element to change its visual state according to a certain predicate. The easiest way to achieve this would be via When function:

 var command = ActionCommand.When(CanExecute).Do(SomeMeaningfulWork);

 void bool CanExecute()
 {  
   //always on
   return true;
 }

 void SomeMeaningfulWork()
 {
   //just chillin'
   return;
 }

Let's have a look at more complex scenario where there is a basic login screen with username and password inputs. The associated command should be enabled only when both the username and the password inputs are not empty. In this case all you have to do is add the correspondent properties with an INotifyPropertyChanged implementation and provide the correct predicate:

        private string _userName;
        public string UserName
        {
            get { return _userName; }
            set
            {
                if (_userName == value)
                    return;
                _userName = value;
                NotifyOfPropertyChange();
            }
        }
       
        private string _password = string.Empty;
        public string Password
        {
            get { return _password; }
            set
            {
                if (_password == value)
                    return;

                _password = value;
                NotifyOfPropertyChange();
            }
        }

        private ICommand _loginCommand;
        public ICommand LoginCommand
        {
            get
            {
                return _loginCommand ??
                       (_loginCommand = ActionCommand
                           .When(() => !string.IsNullOrWhiteSpace(UserName) && !string.IsNullOrWhiteSpace(Password))
                           .Do(Login));
            }
        }

Notifications


There may be cases where you would like the command's execution state to be re-evaluated due to change or changes in some properties which are not part of the predicate. In this case you can use the re-querying options:

        private string _userName;
        public string UserName
        {
            get { return _userName; }
            set
            {
                if (_userName == value)
                    return;
                _userName = value;
                NotifyOfPropertyChange();
            }
        }
       
        private string _password = string.Empty;
        public string Password
        {
            get { return _password; }
            set
            {
                if (_password == value)
                    return;

                _password = value;
                NotifyOfPropertyChange();
            }
        }

        private string _anotherProperty;
        public string AnotherProperty
        {
            get { return _anotherProperty; }
            set
            {
                if (_anotherProperty == value)
                    return;

                _anotherProperty = value;
                NotifyOfPropertyChange();
            }
        }


        private ICommand _loginCommand;
        public ICommand LoginCommand
        {
            get
            {
                return _loginCommand ??
                       (_loginCommand = ActionCommand
                           .When(() => !string.IsNullOrWhiteSpace(UserName) && !string.IsNullOrWhiteSpace(Password))
                           .Do(Login)
                           .RequeryOnPropertyChange(() => AnotherProperty));
            }
        }

There is a multitude of other options, including notification on collection change, on command execution, etc.

Clone this wiki locally