Delegate Commands

  • 8 minutes to read

Delegate commands are an implementation of the System.Windows.Input.ICommand interface, so they can be used to create commands in a ViewModel. A delegate command calls methods (delegates) that you assigned to the command when the command’s Execute and CanExecute logic is invoked.

The following delegate commands are available:

  • DelegateCommand<T> - Specifies a command whose Execute and CanExecute delegates accept a single parameter of type T.
  • DelegateCommand - Specifies a command whose Execute and CanExecute delegates do not have any parameters.

Creating DelegateCommands

Both commands support two constructors: a constructor that accepts an Execute delegate, and a constructor that accepts Execute and CanExecute delegates.

public class DelegateCommandsViewModel : ViewModelBase {
    public DelegateCommand  DelegateCommand1 { get; private set; }
    public DelegateCommand<string> DelegateCommand2 { get; private set; }

    public DelegateCommandsViewModel() {
        DelegateCommand1 = new DelegateCommand(
            () => MessageBoxService.Show("This is a DelegateCommand"));

        DelegateCommand2 = new DelegateCommand<string>(
            x => MessageBoxService.Show(x), 
            x => !string.IsNullOrEmpty(x));
    }
}

CommandParameter Conversion

A DelegateCommand<T> automatically converts the command argument to the parameterized type if possible. In the example below, the CommandParameter (the “Text” string) will be automatically converted to the DocumentType parametrized type.

<Button Command="{Binding ShowDocumentCommand}" CommandParameter="Text"/>
public enum DocumentType { Text, Data }

public class DelegateCommandsViewModel : ViewModelBase {
    public DelegateCommand<DocumentType> ShowDocumentCommand { get; private set; }

    public DelegateCommandsViewModel() {
        ShowDocumentCommand = new DelegateCommand<DocumentType>(ShowDocument);
    }
    void ShowDocument(DocumentType parameter) {
        if(parameter == DocumentType.Text) {
            //... 
        }
        if(parameter == DocumentType.Data) {
            //... 
        }
    }
}

Updating Commands

The DelegateCommand constructors have an optional useCommandManager parameter. This parameter specifies whether a DelegateCommand uses the CommandManager to raise the CanExecuteChanged event. The default setting for useCommandManager is true, which makes it unnecessary to manually implement the disable/enable logic for your commands. Once you set the CanExecute delegate for the command, the delegate is automatically triggered when a user interacts with the UI. When the CommandManager is used for this purpose, the CanExecute handler is called frequently to avoid performing time-consuming operations in the delegate.

If you pass false as the last constructor argument, the CommandManager is not used. In this case, call the RaiseCanExecuteChanged method to update your command.

public class DelegateCommandsViewModel : ViewModelBase {
    public DelegateCommand GoBackCommand{ get; private set; }
    public DelegateCommand GoForwardCommand { get; private set; }

    public DelegateCommandsViewModel() {
        GoBackCommand = new DelegateCommand(GoBack, CanGoBack, false);
        GoForwardCommand = new DelegateCommand(GoForward, CanGoForward, false);
    }

    void GoBack() {
        //... 
        UpdateCommandsState();
    }
    void GoForward() {
        //... 
        UpdateCommandsState();
    }
    bool CanGoBack() {
        //... 
    }
    bool CanGoForward() {
        //... 
    }
    void UpdateCommandsState() {
        GoBackCommand.RaiseCanExecuteChanged();
        GoForwardCommand.RaiseCanExecuteChanged();
    }
}

DelegateCommands in POCO

In a POCO View Model, DelegateCommands can be automatically generated based on public methods (with one parameter or none) of your View Model.

For instance, for the following Save and CanSave methods…

[POCOViewModel]
public class ViewModel {
    public void Save(string fileName) {
        //... 
    }
    public bool CanSave(string fileName) {
        return !string.IsNullOrEmpty(fileName);
    }
}

…the following SaveCommand property is automatically generated.

DelegateCommand<string> saveCommand;
public DelegateCommand<string> SaveCommand {
    get {
        return saveCommand ?? 
            (saveCommand = new DelegateCommand<string>(Save, CanSave));
    }
}

To update an automatically generated command in a POCO View Model, use the RaiseCanExecuteChanged extension method available from the DevExpress.Mvvm.POCO.POCOViewModelExtensions class.

[POCOViewModel]
public class ViewModel {
    public void GoBack(){
        //...
    }
    public bool CanGoBack(){
        //...
    }
    public void UpdateSaveCommand(){
        this.RaiseCanExecuteChanged(c => c.GoBack());
    }
}

Delegate Commands in View Models Generated at Compile Time

To add a DelegateCommand in the View Models Generated at Compile Time, create a void method with the GenerateCommand attribute in your base View Model class.

[GenerateViewModel]
public partial class ViewModel {
    [GenerateCommand]
    void Login(string parameter) {
        //...
    }
    bool CanLogin(string parameter) {
        //...
    }
}
partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);

    DelegateCommand<string> loginCommand;
    public DelegateCommand<string> LoginCommand {
        get => loginCommand ??= new DelegateCommand<string>(Login, CanLogin, true);
    }
}

Commands created in compile time-generated View Models have the default true value in the UseCommandManager attribute property.

If you set the UseCommandManager attribute property to false, you should add the RaiseCanExecuteChanged method to the base View Model.

[GenerateViewModel]
public partial class ViewModel {
    [GenerateCommand(UseCommandManager = false)]
    void Login(string parameter) {
        //...
    }
    bool CanLogin(string parameter) {
        //...
    }

    public void UpdateLoginCommand() => loginCommand.RaiseCanExecuteChanged();
}

Example

This example demonstrates how to create commands with the DelegateCommand class.

View Example

<UserControl x:Class="Example.View.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModel="clr-namespace:Example.ViewModel"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="600">
    <UserControl.DataContext>
        <ViewModel:MainViewModel/>
    </UserControl.DataContext>

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal" Margin="10">
                <Button Content="AutoUpdateCommand" Command="{Binding AutoUpdateCommand}" 
                        Margin="3" VerticalAlignment="Center"/>
                <CheckBox Content="IsAutoUpdateCommandEnabled" IsChecked="{Binding IsAutoUpdateCommandEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                          Margin="3" VerticalAlignment="Center"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="10">
                <Button Content="ManualUpdateCommand" Command="{Binding ManualUpdateCommand}"
                        Margin="3" VerticalAlignment="Center"/>
                <CheckBox Content="IsManualUpdateCommandEnabled" IsChecked="{Binding IsManualUpdateCommandEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                          Margin="3" VerticalAlignment="Center"/>
                <Button Content="ForceUpdateManualUpdateCommand" Command="{Binding ForceUpdateManualUpdateCommand}"
                        Margin="3" VerticalAlignment="Center"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="10">
                <TextBox Text="Message" x:Name="message" Width="80"/>
                <Button Content="CommandWithParameter" Command="{Binding CommandWithParameter}" CommandParameter="{Binding ElementName=message, Path=Text}"
                        Margin="3" VerticalAlignment="Center"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>