我正在尝试在自定义控件上实现ICommandSource(类似于按钮)。目前,实现主要类似于它显示在msom页面上的ICommandSource,并且显示在ButtonBase源代码中。
CanExecute在控件加载时触发,但在任何属性发生更改时不会触发。传递给常规按钮的相同命令工作得很好。当应该更改的属性发生更改时,CanExecute将触发并启用该按钮。该命令是Delegate Command。
我尝试过CommandManager.InvalidateRequerySuggested();但这没效果。
有什么想法吗?
以下是自定义控件中的实现:
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CollapsibleSplitButton csb = (CollapsibleSplitButton)d;
csb.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
}
private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
{
if (oldCommand != null) UnhookCommand(oldCommand);
if (newCommand != null) HookCommand(newCommand);
}
private void UnhookCommand(ICommand command)
{
command.CanExecuteChanged -= OnCanExecuteChanged;
UpdateCanExecute();
}
private void HookCommand(ICommand command)
{
command.CanExecuteChanged += OnCanExecuteChanged;
UpdateCanExecute();
}
private void OnCanExecuteChanged(object sender, EventArgs e)
{
UpdateCanExecute();
}
private void UpdateCanExecute()
{
if (Command != null)
CanExecute = Command.CanExecute(CommandParameter);
else
CanExecute = true;
}
protected override bool IsEnabledCore
{
get { return base.IsEnabledCore && CanExecute; }
}
我在哪里设置命令:
...
MyCommand = new DelegatingCommand(DoStuff, CanDoStuff);
...
private bool CanDoStuff()
{
return (DueDate == null);
}
private void DoStuff() {//do stuff}
答案 0 :(得分:1)
使用delegate
命令,只要您认为应在UI上更新CanExecuteChanged
,就必须明确提升RelayCommand
。尝试使用此版本的命令public class RelayCommand<T> : ICommand
{
#region Fields
readonly Action<T> _execute = null;
readonly Predicate<T> _canExecute = null;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
/// </summary>
/// <param name="execute">Delegate to execute when Execute is called on the command.
///This can be null to just hook up a CanExecute delegate.</param>
/// <remarks><seealso cref="CanExecute"/> will always return true.</remarks>
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
///<summary>
///Defines the method that determines whether the command can execute in its current
///state.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require
/// data to be passed, this object can be set to null.</param>
///<returns>
///true if this command can be executed; otherwise, false.
///</returns>
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute((T)parameter);
}
///<summary>
///Occurs when changes occur that affect whether or not the command should execute.
///</summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
///<summary>
///Defines the method to be called when the command is invoked.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require
///data to be passed, this object can be set to <see langword="null" />.</param>
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion
}
-
Delegate
在您的班级中注册public ICommand TestCommand { get; private set; }
TestCommand = new RelayCommand<object>(CommandMethod, CanExecuteCommand);
命令 -
CommandManager.InvalidateRequerySuggested();
修改强>
尝试将CanExecute
放入private void OnCanExecuteChanged(object sender, EventArgs e)
{
CommandManager.InvalidateRequerySuggested();
UpdateCanExecute();
}
-
{{1}}
答案 1 :(得分:0)
通过将回调包装在EventHandler中来管理解决问题。
private EventHandler currentHandler;
private void UnhookCommand(ICommand command)
{
if (currentHandler != null)
command.CanExecuteChanged -= currentHandler;
UpdateCanExecute();
}
private void HookCommand(ICommand command)
{
if (currentHandler == null) return;
command.CanExecuteChanged += currentHandler;
UpdateCanExecute();
}