Reputation: 8208
I'm learning ICommands in WPF and I ran into a problem with some simple code. I have a Button with a Command. If I set the command parameter to a static value like this, CommandParameter="100"
, the value of the parameter
argument in CanExecute is 100, however when I set the value of the command parameter via binding like this CommandParameter="{Binding}"
, the value of the parameter
argument in CanExecute is null.
Here's my ICommand:
internal class MyCommand : ICommand
{
public bool CanExecute(object parameter) //parameter is null
{
var datacontext = parameter as MyDataContext;
if (datacontext == null)
return false;
return datacontext.IsChecked == true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
throw new NotImplementedException();
}
}
Here's the XAML code. Notice that I'm setting the CommandParameter before setting the Command. I got that from here. Again, if I change the CommandParameter to somwthing like CommandParameter="100"
, the code acts as I would expect (i.e., the parameter is 100, not null).
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<cmd:MyCommand x:Key="kCmd" />
</StackPanel.Resources>
<CheckBox Content="Check this to enable button" IsChecked="{Binding IsChecked}" />
<Button Content="Click" CommandParameter="{Binding}"
Command="{StaticResource kCmd}" />
</StackPanel>
Here's my MainWindow code-behind. Here, I'm setting the DataContext before calling InitializeComponent()
. While debugging, I found that InitializeComponent()
triggers a call to the ICommand's CanExecute(object)
.
public MainWindow()
{
this.DataContext = new MyDataContext();
InitializeComponent();
}
My MyDataContext
class is pretty simple, so I left it out.
Upvotes: 6
Views: 4532
Reputation: 1622
It is also a solution to force reevaluation of CanExecute
from the on Loaded
of a FrameworkElement
event by raising the CanExecuteChanged
event of the command. This approach can especially be used, when you are working with DataTemplate
s, and you are experiencing this problem.
Example:
<DataTemplate x:Key="MyTemplate">
<Grid Loaded="HandleLoaded">
...
And code behind:
void HandleLoaded(object sender, RoutedEventArgs e)
{
var viewModel = this.DataContext as ViewModel;
if (viewModel != null)
{
viewModel.DoItCommand.RaiseCanExecuteChanged();
}
}
Another possible solution, which may works, is to define the binding to the command itself as IsAsync=True
. But this will result in some flickering. So it is maybe not the best choice.
Example: {Binding DoItCommand, IsAsync=True}
Upvotes: 4
Reputation: 1330
Try raising the CanExecuteChanged
-event of the MyCommand
class after InitializeComponent()
has finished. Probably, the CanExecute(object)
of MyCommand
is called to initialize the state of the button when rendering the first time, while the bindings have not all yet been initialized.
Upvotes: 1