WPF DelegateCommand how to control when CanExecute method is called

350 Views Asked by At

I have a checkbox on a grid column that has a command assigned to it. My CanExecute method is firing when I load the window and for each item in the grid even if I haven't clicked the check box. I end up with a loop of messagebox dialogs to close.

It doesn't seem to fire as often if the focus is not lost, but it's still firing before I click a box.

Ideally I'd like for it not to run at all unless I check the checkbox. I'm using the DelegateCommand from Microsoft.VisualStudio.Utilities.

<DataGrid ItemsSource="{Binding Employees}" CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Register">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.CheckboxRegisterCommand}"></CheckBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

And the viewmodel:

Public Property CheckboxRegisterCommand As DelegateCommand
Public Sub New()
    CheckboxRegisterCommand = New DelegateCommand(AddressOf Register, AddressOf CanRegister)

    Employees = New ObservableCollection(Of Employee) From
    {
        New Employee(),
        New Employee(),
        New Employee()
    }
End Sub

Private Function CanRegister() As Boolean
    MessageBox.Show("Can Register..")
    Return True
End Function
Private Sub Register()
    MessageBox.Show("Registering")
End Sub
1

There are 1 best solutions below

0
On

You appear to have fundamentally misunderstood canexecute and or commanding.

In order to drive whether users can run a command there is a mechanism which will query the canexecute of every command you have in a view.

You can call that in code using CommandManager.InvalidateRequerySuggested()

https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.commandmanager.invalidaterequerysuggested?view=netframework-4.8#System_Windows_Input_CommandManager_InvalidateRequerySuggested

This is also raised every time there is what is considered meaningful user interaction with the view.

It returns true - the command can execute and the bound control is enabled, or false and the command cannot execute - the control is disabled.

This is the behaviour you are seeing.

Every time the user clicks a button, types text, selects a combo item etc. then every command will have it's canexecute called.

You should not be putting a messagebox in that. It's not just any old method you can override. It should return true or false and any logic it calls should run as quickly as you can possibly make it.

You already show a messagebox in the command. I don't follow why you have this code in canexecute at all and canexecute is supposed to return a bool. I do c# but isn't that a function in vb rather than a sub?