当命令 CanExecute 为 false 时,按钮不会被禁用
Posted
技术标签:
【中文标题】当命令 CanExecute 为 false 时,按钮不会被禁用【英文标题】:Button doesn't become disabled when command CanExecute is false 【发布时间】:2013-02-08 13:45:22 【问题描述】:我有一个简单的窗口,带有一个按钮,通过命令绑定到 ViewModel。
如果 MyCommand.CanExecute() 为 false,我希望按钮被禁用。但似乎 WPF 只会在第一次绘制窗口时设置 IsEnabled 属性。任何后续操作都不会影响按钮的可见状态。我正在使用 Prism 的 DelegateCommand。
我的观点:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Click Here" Command="Binding MyCommand" Width="100" Height="50"/>
</Grid>
还有我的 ViewModel:
public class MyVM : NotificationObject
public MyVM()
_myCommand = new DelegateCommand(DoStuff, CanDoStuff);
private void DoStuff()
Console.WriteLine("Command Executed");
_myCommand.RaiseCanExecuteChanged();
private bool CanDoStuff()
var result = DateTime.Now.Second % 2 == 0;
Console.WriteLine("CanExecute is 0", result);
return result;
private DelegateCommand _myCommand;
public ICommand MyCommand
get
return _myCommand;
50% 的时间,当我的应用程序加载时,该按钮被正确禁用。但是,如果它在窗口加载时启用,并且我单击按钮执行命令,我预计 50% 的时间按钮会被禁用,但它永远不会。该命令不执行,但我仍然可以单击该按钮。如何让 WPF 了解当 CanExecute() 为 false 时应禁用该按钮?
【问题讨论】:
您需要做的第一件事是打开数据绑定的调试消息:i.stack.imgur.com/MF8i5.png 接下来,重新运行并检查输出窗口,看看有什么错误。如果没有与您的命令绑定相关,那么您的RaiseCanExecuteChanged()
实现不正确/有问题。
你的 CanDOStuff 方法真的很奇怪!它可能会使您的按钮被禁用,但在下一秒您的命令可以执行,但按钮被禁用......真的很奇怪。但如果您的 CanExecute 可能会更改并且 UI 未更新,因为 CanExecuteChanged 未引发,您应该致电 CommandManager.InvalidateRequerySuggested()。
@Viktor 我知道这很奇怪,它应该是一个随机返回真/假的愚蠢示例。 CommandManager.InvalidateRequerySuggested 无效。
@Will 输出中没有错误,RaiseCanExecuteChanged
是 Microsoft Prism 库的一部分,不是自产的。
【参考方案1】:
我看到您正在使用 Prism 及其 NotificationObject
和 DelegateCommand
,因此我们应该期望 RaiseCanExecuteChanged() 中不会出现错误。
但是,该行为的原因是 Prism 的 RaiseCanExecuteChanged 同步运行,因此在我们仍在 ICommand.Execute()
的实现中时调用了 CanDoStuff()
,然后结果似乎被忽略了。
如果您使用自己的命令创建另一个按钮并从该命令/按钮调用_myCommand.RaiseCanExecuteChanged()
,则第一个按钮将按照您的预期启用/禁用。
或者,如果您使用 MVVM Light 和 RelayCommand 尝试相同的操作,您的代码将工作,因为 MVVM Light 的 RaiseCanExecuteChanged
调用 CommandManager.InvalidateRequerySuggested()
,它使用 Dispatcher.CurrentDispatcher.BeginInvoke
异步调用对 CanDoStuff
的回调,避免了您的行为看看 Prism 的实现。
【讨论】:
感谢您的解释。我尝试了您的两个建议,并且它们都是正确的。似乎是 Prism 的不幸限制。【参考方案2】:你可以试试这个(Microsoft.Practices.Prism.dll
是必须的)
public class ViewModel
public DelegateCommand ExportCommand get;
public ViewModel()
ExportCommand = new DelegateCommand(Export, CanDoExptor);
private void Export()
//logic
private bool _isCanDoExportChecked;
public bool IsCanDoExportChecked
get return _isCanDoExportChecked;
set
if (_isCanDoExportChecked == value) return;
_isCanDoExportChecked = value;
ExportCommand.RaiseCanExecuteChanged();
private bool CanDoExptor()
return IsCanDoExportChecked;
【讨论】:
以上是关于当命令 CanExecute 为 false 时,按钮不会被禁用的主要内容,如果未能解决你的问题,请参考以下文章
WPF - 如果命令的 CanExecute 为假,如何隐藏菜单项?
WPF - 如何强制命令通过其 CommandBindings 重新评估“CanExecute”
WPF MVVM Command CanExecute,仅在焦点更改时重新评估
Prism DelegateCommand 中的 CanExecute 不起作用