My following code is Implementing a custom WPF Command. I have bonded only the first button (titled Exit) with the CommandBinding
so that when Exit
button is clicked and e.CanExecute
is true in CommandBinding_CanExecute
event, the CommandBinding_Executed
event closes the app. This scenario works fine with Exit button. But, when btnTest
button - that is not bonded with any command - is clicked, CommandBinding_CanExecute
event also gets called. This can be tested by placing a breakpoint on the btnTest_Click
event and noticing that after the code exits this event the cursor goes to CommandBinding_CanExecute
event.
Question: Why the btnTest
button is also calling CommandBinding_CanExecute
event despite that fact that CommandBinding
is used only on Exit
button. What I may be missing here, and how can we fix the issue?
Remarks For brevity I have simplified the issue. But in real scenario e.CanExecute
value in CommandBinding_CanExecute
is set to true by calling a function that performs a long complex logic that returns true or false based on certain scenario for the Exit button. And I don't want that long logic to be performed when other buttons (e.g. btnTest
) is clicked.
MainWindow.Xaml:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Exit" Command="local:CustomCommands.Exit">
<Button.CommandBindings>
<CommandBinding Command="local:CustomCommands.Exit" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/>
</Button.CommandBindings>
</Button>
<Button x:Name="btnTest" Content="Test" Click="btnTest_Click" Margin="10"/>
</StackPanel>
</Grid>
</Window>
MainWindow.Xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnTest_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Why this event is calling ExitCommand_CanExecute");
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
public static class CustomCommands
{
public static readonly RoutedUICommand Exit = new RoutedUICommand
(
"Exit",
"Exit",
typeof(CustomCommands),
new InputGestureCollection()
{
new KeyGesture(Key.F4, ModifierKeys.Alt)
}
);
}
What makes you think
btnTest
is callingCommandBinding_CanExecute
? It doesn't.The
CanExecute
method of the command is called by theCommandManager
whenever it wants to know the current status of the command. You don't control when this happens. The framework does. It's not connected to thebtnTest
.If you have some complex logic in
CanExecute
, you should consider creating a custom command class that implements theICommand
interface and raise theCanExecuteChanged
event whenever you want the framework to refresh the status of the command by calling itsCanExecute
method. This way you can control when the command should be refreshed.You could then bind the
Command
property of theButton
to an instance of your custom command class. If you google for "DelegateCommand" or "RelayCommand", you should find a lot of examples. This blog post may be a good starting point.