wpf-17353-mvvm-framework-commands-delegate-commands.md
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:
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));
}
}
Public Class DelegateCommandsViewModel
Inherits ViewModelBase
Public Property DelegateCommand1 As DelegateCommand
Public Property DelegateCommand2 As DelegateCommand(Of String)
Public Sub New()
DelegateCommand1 = New DelegateCommand(Function() MessageBoxService.Show("This is a DelegateCommand"))
DelegateCommand2 = New DelegateCommand(Of String)(Function(x) MessageBoxService.Show(x), Function(x) Not String.IsNullOrEmpty(x))
End Sub
End Class
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) {
//...
}
}
}
Public Enum DocumentType
Text
Data
End Enum
Public Class DelegateCommandsViewModel
Inherits ViewModelBase
Public Property ShowDocumentCommand As DelegateCommand(Of DocumentType)
Public Sub New()
ShowDocumentCommand = New DelegateCommand(Of DocumentType)(AddressOf ShowDocument)
End Sub
Private Sub ShowDocument(ByVal parameter As DocumentType)
If parameter = DocumentType.Text Then
End If
If parameter = DocumentType.Data Then
End If
End Sub
End Class
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();
}
}
Public Class DelegateCommandsViewModel
Inherits ViewModelBase
Public Property GoBackCommand As DelegateCommand
Public Property GoForwardCommand As DelegateCommand
Public Sub New()
GoBackCommand = New DelegateCommand(AddressOf GoBack, AddressOf CanGoBack, False)
GoForwardCommand = New DelegateCommand(AddressOf GoForward, AddressOf CanGoForward, False)
End Sub
Private Sub GoBack()
UpdateCommandsState()
End Sub
Private Sub GoForward()
UpdateCommandsState()
End Sub
Private Function CanGoBack() As Boolean
End Function
Private Function CanGoForward() As Boolean
End Function
Private Sub UpdateCommandsState()
GoBackCommand.RaiseCanExecuteChanged()
GoForwardCommand.RaiseCanExecuteChanged()
End Sub
End Class
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);
}
}
<POCOViewModel>
Public Class ViewModel
Public Sub Save(fileName As String)
'...
End Sub
Public Function CanSave(fileName As String) As Boolean
Return Not String.IsNullOrEmpty(fileName)
End Function
End Class
…the following SaveCommand property is automatically generated.
DelegateCommand<string> saveCommand;
public DelegateCommand<string> SaveCommand {
get {
return saveCommand ??
(saveCommand = new DelegateCommand<string>(Save, CanSave));
}
}
Dim _SaveCommand As DelegateCommand(Of String)
Public ReadOnly Property SaveCommand
Get
If (_SaveCommand Is Nothing) Then
_SaveCommand = New DelegateCommand(Of String)(AddressOf Save, AddressOf CanSave)
End If
Return _SaveCommand
End Get
End Property
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());
}
}
<POCOViewModel>
Public Class ViewModel
Public Sub GoBack()
'...
End Sub
Public Function CanGoBack() As Boolean
'...
End Function
Public Sub UpdateSaveCommand()
Me.RaiseCanExecuteChanged(Sub(c) c.GoBack())
End Sub
End Class
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();
}
You can use the CommandAttribute to create commands in POCO View Models and ViewModelBase descendants.
public class ViewModel : ViewModelBase {
[Command]
public void Save() {
//...
}
public bool CanSave() {
//...
}
}
Public Class ViewModel
Inherits ViewModelBase
<Command>
Public Sub Save()
'...
End Sub
Public Function CanSave() As Boolean
'...
End Function
End Class
Refer to the following help topic for more information: Create Commands Without Command Properties.