[ACCEPTED]-Refresh WPF Command-updating
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.
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.
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.
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}"/>
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
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.