[ACCEPTED]-Refresh WPF Command-updating

Accepted answer
Score: 105

Calling System.Windows.Input.CommandManager.InvalidateRequerySuggested() forces the CommandManager to raise 9 the RequerySuggested event.

Remarks: The CommandManager 8 only pays attention to certain conditions 7 in determining when the command target has 6 changed, such as change in keyboard focus. In 5 situations where the CommandManager does 4 not sufficiently determine a change in conditions 3 that cause a command to not be able to execute, InvalidateRequerySuggested 2 can be called to force the CommandManager 1 to raise the RequerySuggested event.

Score: 29

I was aware of CommandManager.InvalidateRequerySuggested() a 9 long time ago, and used it, but it wasn't 8 working for me sometimes. I finally figured 7 out why this was the case! Even though it 6 doesn't throw like some other actions, you 5 HAVE to call it on the main thread.

Calling 4 it on a background thread will appear to 3 work, but sometimes leave the UI disabled. I 2 really hope this helps somebody, and saves 1 them the hours I just wasted.

Score: 17

A workaround for that is binding IsEnabled to a property:

<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>

and 6 then implement this property in your ViewModel. This 5 also makes it a bit easier for the UnitTesting 4 to work with the properties rather than 3 commands to see if the command can be executed 2 at a certain point of time.

I, personally, find 1 it more convenient.

Score: 6

Probably this variant will suit you:

 public interface IRelayCommand : ICommand
{
    void UpdateCanExecuteState();
}

Implementation:

 public class RelayCommand : IRelayCommand
{
    public event EventHandler CanExecuteChanged;


    readonly Predicate<Object> _canExecute = null;
    readonly Action<Object> _executeAction = null;

   public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
    {
        _canExecute = canExecute;
        _executeAction = executeAction;
    }


    public bool CanExecute(object parameter)
    {
       if (_canExecute != null)
            return _canExecute(parameter);
        return true;
    }

    public void UpdateCanExecuteState()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, new EventArgs());
    }



    public void Execute(object parameter)
    {
        if (_executeAction != null)
            _executeAction(parameter);
        UpdateCanExecuteState();
    }
}

Using 1 simple:

public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);

 protected override bool CanEditCommandExecuted(object obj)
    {
        return SelectedItem != null ;
    }

    protected override void EditCommandExecuted(object obj)
    {
        // Do something
    }

   ...

    public TEntity SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;

            //Refresh can execute
            EditCommand.UpdateCanExecuteState();

            RaisePropertyChanged(() => SelectedItem);
        }
    }

XAML:

<Button Content="Edit" Command="{Binding EditCommand}"/>
Score: 4

Thanks guys for the tips. Here's a bit of 4 code on how to marshal that call from a 3 BG thread to the UI thread:

private SynchronizationContext syncCtx; // member variable

In the constructor:

syncCtx = SynchronizationContext.Current;

On 2 the background thread, to trigger the requery:

syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );

Hope 1 that helps.

-- Michael

Score: 0

To update only a single GalaSoft.MvvmLight.CommandWpf.RelayCommand 2 you could use

mycommand.RaiseCanExecuteChanged();

and for me i've created an 1 Extension method:

public static class ExtensionMethods
    {
        public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
        }

        public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
        }
    }

More Related questions