I have two commands that I want to trigger via a button click. So I've created a CompositeCommand
, registered my two commands with it, and bound to my button. My commands are DelegateCommands
.
The problem is that the button is disabled and I can't enable it.
I've tried adding trivial CanExecute
methods to the DeleteCommands
, but that didn't fix it.
I've tried setting monitorCommandActivity
to true in the CompositeCommand
constructor.
I thought maybe it was disabling because my DelegateCommands
have parameters and a CompositeCommand
doesn't seem to be able to take any CommandParameters
, but I eliminated the parameters in the DelegateCommands
and that didn't fix the problem.
View.xaml:
<TextBlock Text="Theme:" />
<telerik:RadComboBox x:Name="_themeComboBox"
ItemsSource="{Binding ThemeList}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedTheme, Mode=TwoWay}" />
<telerik:RadButton Content="Apply"
Command="{Binding ThemeApplyAndSaveCommand}" />
ViewModel.cs:
public class ViewModel
{
public ViewModel(ILogger logger, ...)
{
ThemeList = _userSettingsService.GetThemeList();
// Configure the theme Apply button to both select and save the theme
ThemeApplyAndSaveCommand.RegisterCommand(ThemeApplyCommand);
ThemeApplyAndSaveCommand.RegisterCommand(ThemeSaveCommand);
// Activate the user's preferred theme
SelectedTheme = _userSettingsService.GetThemePreference(securityContext.User);
ThemeApplyCommand.Execute();
logger.Debug(" ThemeApplyCommand.CanExecute: {canExecute}", ThemeApplyCommand.CanExecute());
logger.Debug(" ThemeSaveCommand.CanExecute: {canExecute}", ThemeSaveCommand.CanExecute());
logger.Debug(" ThemeApplyAndSaveCommand.CanExecute: {canExecute}", ThemeApplyAndSaveCommand.CanExecute(null));
}
public CompositeCommand ThemeApplyAndSaveCommand => new CompositeCommand();
public DelegateCommand ThemeApplyCommand => new DelegateCommand(ExecuteThemeApplyCommand);
public DelegateCommand ThemeSaveCommand => new DelegateCommand(ExecuteThemeSaveCommand);
private void ExecuteThemeApplyCommand()
{
...
}
private void ExecuteThemeSaveCommand()
{
...
}
}
You have to register DelegateCommand
s to a CompositeCommand
using the RegisterCommand
method. Directly adding them to the RegisteredCommands
collection does not work, as it returns a new collection instance each time.
var compositeCommand = new CompositeCommand();
compositeCommand.RegisterCommand(MyDelgateCommand);
compositeCommand.RegisterCommand(MyOtherDelegateCommand);
A CompositeCommand
only returns true
for CanExecute
, if all active commands can execute. You have to make sure to call RaiseCanExecuteChanged
when the registered commands should update their activity, so the composite command can reevaluate its activity, too.
Monitoring the command activity is something completely different. Views or view models in Prism can implement IActiveAware
to know when they are activated and deactivated in a region. DelegateCommands
implement this interface too, so they can also be activated and deactivated with their corresponding view model. If you do not explicitly enable monitoring command activity, commands will be treated as if they are active.
Imagine a command to save the active document in a tab control. You could register save commands of the tabs to a common save CompositeCommand
, but activate them only if they are on the active tab. In that case, monitoring the activity of the commands will only consider active commands for CanExecute
and will execute only them, when the command is invoked.
Update on your posted code. The corresponding command properties return new commands each time. Initialize the composite command and the other commands in the constructor.
public ViewModel(ILogger logger, ...)
{
ThemeList = _userSettingsService.GetThemeList();
// Configure the theme Apply button to both select and save the theme
ThemeApplyAndSaveCommand = new CompositeCommand();
ThemeApplyCommand = new DelegateCommand(ExecuteThemeApplyCommand);
ThemeSaveCommand = new DelegateCommand(ExecuteThemeSaveCommand);
ThemeApplyAndSaveCommand.RegisterCommand(ThemeApplyCommand);
ThemeApplyAndSaveCommand.RegisterCommand(ThemeSaveCommand);
// ...the rest of the constructor code.
}
public CompositeCommand ThemeApplyAndSaveCommand { get; }
public DelegateCommand ThemeApplyCommand { get; }
public DelegateCommand ThemeSaveCommand { get; }