wpf 当命令 CanExecute 为 false 时,按钮不会被禁用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15032689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Button doesn't become disabled when command CanExecute is false
提问by Greg Ferreri
I have a simple-as-can be window with a button tied to a ViewModel with a command.
我有一个简单的窗口,其中有一个按钮与带有命令的 ViewModel 绑定。
I expect the button to be disabled if MyCommand.CanExecute() is false. But it seems that WPF will only set the IsEnabled property when the window is first drawn. Any subsequent action does not effect the button's visible state. I am using a DelegateCommand from Prism.
如果 MyCommand.CanExecute() 为 false,我希望按钮被禁用。但似乎WPF只会在第一次绘制窗口时设置IsEnabled属性。任何后续操作都不会影响按钮的可见状态。我正在使用 Prism 的 DelegateCommand。
My View:
我的看法:
<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>
and my 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% of the time, when my application loads, the button is properly disabled. However, if it's enabled when the window loads, and I click the button to execute the command, I expect 50% of the time for the button to become disabled, but it never does. The command does not execute, but I can still click the button. How do I get WPF to understand that the button should be disabled when CanExecute() is false?
50% 的情况下,当我的应用程序加载时,按钮会被正确禁用。但是,如果它在窗口加载时启用,并且我单击按钮来执行命令,我希望该按钮有 50% 的时间被禁用,但它永远不会。该命令不执行,但我仍然可以单击该按钮。如何让 WPF 了解当 CanExecute() 为 false 时应禁用该按钮?
采纳答案by Phil
I see you're using Prism and its NotificationObjectand DelegateCommand, so we should expect there not to be a bug in RaiseCanExecuteChanged().
我看到您正在使用 Prism 及其NotificationObjectand DelegateCommand,因此我们应该期望 RaiseCanExecuteChanged() 中不会出现错误。
However, the reason for the behaviour is that Prism's RaiseCanExecuteChanged operates synchronously, so CanDoStuff()is called while we're still inside the implementation of ICommand.Execute()and the result then appears to be ignored.
但是,这种行为的原因是 Prism 的 RaiseCanExecuteChanged 是同步操作的,因此 CanDoStuff()在我们仍在 的实现中时被调用,ICommand.Execute()结果似乎被忽略了。
If you create another button with its own command and call _myCommand.RaiseCanExecuteChanged()from that command/button, the first button will be enabled/disabled as you expect.
如果您使用自己的命令创建另一个按钮并_myCommand.RaiseCanExecuteChanged()从该命令/按钮调用,第一个按钮将按预期启用/禁用。
Or, if you try the same thing with MVVM Light and RelayCommand your code will work because MVVM Light's RaiseCanExecuteChangedcalls CommandManager.InvalidateRequerySuggested()which invokes the callback to CanDoStuffasynchronously using Dispatcher.CurrentDispatcher.BeginInvoke, avoiding the behaviour you're seeing with Prism's implementation.
或者,如果您使用 MVVM Light 和 RelayCommand 尝试相同的事情,您的代码将起作用,因为 MVVM Light 的RaiseCanExecuteChanged调用CommandManager.InvalidateRequerySuggested()会CanDoStuff异步调用回调,从而Dispatcher.CurrentDispatcher.BeginInvoke避免使用 Prism 实现时看到的行为。
回答by isxaker
You can try this (Microsoft.Practices.Prism.dllis necessary)
你可以试试这个(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;
}
}

