Harry Boy
Harry Boy

Reputation: 4777

WPF CanExecute not being called every time

I have the following code in my WPF Application that I use to enable or disable buttons on my UI

XAML

<Button x:Name="FirstButton" Command="{x:Static local:MyClass.CommandOne}"/>
<Button x:Name="FirstButton" Command="{x:Static local:MyClass.CommandTwo}"/>

Code Behind

CommandBindings.Add(new CommandBinding(CommandOne, CommandOne_Executed, CommandOne_CanExecute));
CommandBindings.Add(new CommandBinding(CommandTwo, CommandTwo_Executed, CommandTwo_CanExecute));

public static readonly RoutedUICommand CommandOne = new RoutedUICommand();
public static readonly RoutedUICommand CommandTwo = new RoutedUICommand();

private void CommandOne_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (e != null)
        e.CanExecute = (_currentValue > 1);
}

private void CommandTwo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (e != null)
        e.CanExecute = (_currentValue > 100);
}

Worker Code

private async Task DoSomeWork(int value)
{
    await Task.Run(() =>
    {
        // Do some work on value
        _currentValue = value
    }
}

What I find is that when the values of _currentValue change due to some processing sometimes the CommandOne_CanExecute and CommandTwo_CanExecute functions do not get called. If I then e.g. move the UI they will then be called. How can I ensure that these are called everytime.

Upvotes: 0

Views: 1573

Answers (2)

mm8
mm8

Reputation: 169400

You could call the CommandManager.InvalidateRequerySuggested() method to invalidate all commands.

What you should do however is to implement your own command - it is simply a class that implements the ICommand interface - and raise the CanExecuteChanged event of the command whenever you want the CanExecute method to get called.

Or you could use any of the implementations of the ICommand that are included in any of the MVVM frameworks out there. You could for example take a look at how the RelayCommand class is implemented in MvvmLight: https://github.com/paulcbetts/mvvmlight/blob/master/GalaSoft.MvvmLight/GalaSoft.MvvmLight%20(NET35)/Command/RelayCommand.cs.

It has a RaiseCanExecuteChanged() method that you can call to raise the CanExecuteChanged event of the command. This will cause the CanExecute method to get invoked and the command to be invalidated.

The built-in RoutedUICommand class has no such method I am afraid.

Upvotes: 3

Krishna
Krishna

Reputation: 1985

You need to create a property for CurrentValue instead of a variable and raisecanexecutechanged event Try below code

    private int _currentValue = false;
    public bool CurrentValue
    {
        get { return _currentValue; }
        set 
          { 
              if(_currentValue != value)
                CommandManager.InvalidateRequerySuggested();
              SetProperty(ref _currentValue, value); 

          }
    }

CommandBindings.Add(new CommandBinding(CommandOne, CommandOne_Executed, CommandOne_CanExecute));
CommandBindings.Add(new CommandBinding(CommandTwo, CommandTwo_Executed, CommandTwo_CanExecute));

public static readonly RoutedUICommand CommandOne = new RoutedUICommand();
public static readonly RoutedUICommand CommandTwo = new RoutedUICommand();

private void CommandOne_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (e != null)
        e.CanExecute = (CurrentValue > 1);
}

private void CommandTwo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (e != null)
        e.CanExecute = (CurrentValue > 100);
}

private async Task DoSomeWork(int value)
{
    await Task.Run(() =>
    {
        // Do some work on value
        CurrentValue = value
    }
}

Upvotes: 0

Related Questions