KGy SOFT

ICommand Interface

KGy SOFT Core Libraries Help
Represents a command, which can be used to create a binding between an event of one or more sources and zero or more target objects. Can be used easily to bind events with targets with any technology.
See the Remarks section for details.

Namespace:  KGySoft.ComponentModel
Assembly:  KGySoft.CoreLibraries (in KGySoft.CoreLibraries.dll) Version: 5.0.0-rc.1
Syntax

public interface ICommand

The ICommand type exposes the following members.

Methods

  NameDescription
Public methodExecute
Executes the command invoked by the specified source for the specified target.
Top
Extension Methods

  NameDescription
Public Extension MethodCreateBinding(IDictionaryString, Object, Boolean)Overloaded.
Creates a binding for a command without any sources and targets. At least one source must be added by the ICommandBinding.AddSource method to make the command invokable. Targets can be added by the ICommandBinding.AddTarget method.
(Defined by Command.)
Public Extension MethodCreateBinding(Object, String, Object)Overloaded.
Creates a binding for a command using the specified source, eventName and targets.
(Defined by Command.)
Public Extension MethodCreateBinding(Object, String, IDictionaryString, Object, Object)Overloaded.
Creates a binding for a command using the specified source, eventName and targets as well as the optionally provided initial state of the binding.
(Defined by Command.)
Top
Remarks

Unlike the System.Windows.Input.ICommand type, this ICommand represents a stateless command so the implementations are best to be accessed via static members. The command states (such as Enabled or any other status) belong to the created binding represented by the ICommandBinding interface and can be accessed by the ICommandBinding.State property, which returns an ICommandState instance.

To implement a command by using a delegate you can also choose one of the four predefined classes: SimpleCommand, TargetedCommandTTarget, SourceAwareCommandTEventArgs and SourceAwareTargetedCommandTEventArgs, TTarget depending whether the command targets specific objects and behaves differently based on the source's state or event arguments.

A binding can be created by the Commands.CreateBinding methods or by the CommandBindingsCollection class. When a binding or a collection of bindings are disposed all of the event subscriptions are released, which makes the cleanup really simple.

Examples

Tip Tip
Try also online.
The following examples demonstrate how to define different kind of commands:
C#
public static partial class MyCommands
{
    // A simple command with no target and ignored source: (assumes we have an ExitCode state)
    public static ICommand CloseApplicationCommand =>
        new SimpleCommand(state => Environment.Exit((int)state["ExitCode"])); // or: .Exit(state.AsDynamic.ExitCode)

    // A source aware command, which can access the source object and the triggering event data
    public static ICommand LogMouseCommand =>
        new SourceAwareCommand<MouseEventArgs>((source, state) => Debug.WriteLine($"Mouse coordinates: {source.EventArgs.X}; {source.EventArgs.Y}"));

    // A targeted command (also demonstrates how to change the command state of another command):
    public static ICommand ToggleCommandEnabled =>
        new TargetedCommand<ICommandState>((state, targetState) => targetState.Enabled = !targetState.Enabled);

    // A source aware targeted command:
    public static ICommand ProcessKeysCommand => new SourceAwareTargetedCommand<KeyEventArgs, Control>(OnProcessKeysCommand);

    private static void OnProcessKeysCommand(ICommandSource<KeyEventArgs> source, ICommandState state, Control target)
    {
        // do something with target by source.EventArgs
    }
}
And a binding for a command can be created in an application, with any kind of UI, which uses events, or even without any UI: only event sources are needed.
C#
public class MyView : SomeViewBaseWithEvents // base can be a Window in WPF or a Form in WindowsForms or simply any component with events.
{
    private ICommandBinding exitBinding;

    private CommandBindingsCollection commandBindings = new CommandBindingsCollection();

    public MyView()
    {
        // ...some initialization of our View...

        // Simplest case: using the CreateBinding extension on ICommand.
        // Below we assume we have a menu item with a Click event.
        // We set also the initial status. By adding the property state updater the
        // states will be applied on the source as properties.
        exitBinding = MyCommands.CloseApplicationCommand.CreateBinding(
            new Dictionary<string, object>
            {
                { "Text", "Exit Application" },
                { "ShortcutKeys", Keys.Alt | Keys.F4 },
                { "ExitCode", 0 },
            })
           .AddStateUpdater(PropertyCommandStateUpdater.Updater)
           .AddSource(menuItemExit, "Click");

        // If we add the created bindings to a CommandBindingsCollection, then all of them can be disposed at once by disposing the collection.
        commandBindings.Add(exitBinding);

        // We can create a binding by the Add methods of the collection, too:
        // As we added the property state updater to the exitBinding the menuItemExit.Enabled property will reflect the command state.
        var toggleEnabledBinding = commandBindings.Add(MyCommands.ToggleCommandEnabledCommand, buttonToggle, "Click", exitBinding.State);

        // The line above can be written by a more descriptive fluent syntax (and that's how multiple sources can be added):
        var toggleEnabledBinding = commandBindings.Add(MyCommands.ToggleCommandEnabledCommand)
            .AddSource(buttonToggle, nameof(Button.Click))
            .AddTarget(exitBinding.State);

        // If we set the state of a binding with a property updater it will be applied for all sources (only if a matching property exists):
        exitBinding.State["Text"] = "A new text for the exit command";

        // Or as dynamic:
        toggleEnabledBinding.State.AsDynamic.Text = "A new text for the exit command";
    }

    protected override Dispose(bool disposing)
    {
        base.Dispose(disposing);

        // disposing a CommandBindingsCollection will release all of the internal event subscriptions at once
        if (disposing)
            commandBindings.Dispose();
    }
}
See Also

Reference