C# PropertyChanged 后 ICommand CanExecute 不触发?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14479303/
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
ICommand CanExecute not triggering after PropertyChanged?
提问by nabulke
I got a WPF applicationthat shows a button bound to a command like that:
我有一个WPF 应用程序,它显示一个绑定到命令的按钮,如下所示:
<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">
The command is defined like that:
该命令定义如下:
public ICommand TestrunStartCommand
{
get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); }
}
public bool IsTestrunInProgress
{
get{
return _isTestrunInProgress;
}
set{
_isTestrunInProgress = value;
RaisePropertyChanged(IsTestrunInProgressPropertyName);
}
}
The problem is, the button won't be enabled immediately after I set IsTestrunInProgress
to false, but only after I click inside the application window.
问题是,该按钮在我设置IsTestrunInProgress
为 false后不会立即启用,而是在我在应用程序窗口内单击后才启用。
Could you help me understand this behaviour and show me how to fix this?
你能帮我理解这种行为并告诉我如何解决这个问题吗?
Further reading:wpf command pattern - when does it query canexecute
采纳答案by Lukazoid
The ICommand
interface exposes an event ICommand.CanExecuteChanged
which is used to inform the UI when to re-determine the IsEnabled
state of command driven UI components.
该ICommand
接口公开了一个事件ICommand.CanExecuteChanged
,用于通知 UI 何时重新确定IsEnabled
命令驱动的 UI 组件的状态。
Depending upon the implementation of the RelayCommand
you are using, you may need to raise this event; Many implementations expose a method such as RelayCommand.RaiseCanExecuteChanged()
which you can invoke to force the UI to refresh.
根据RelayCommand
您正在使用的实现,您可能需要引发此事件;许多实现公开了一个方法,例如RelayCommand.RaiseCanExecuteChanged()
您可以调用它来强制刷新 UI。
Some implementations of the RelayCommand
make use of CommandManager.RequerySuggested
, in which case you will need to call CommandManager.InvalidateRequerySuggested()
to force the UI to refresh.
RelayCommand
make use of 的 一些实现CommandManager.RequerySuggested
,在这种情况下,您需要调用CommandManager.InvalidateRequerySuggested()
以强制刷新 UI。
Long story short, you will need to call one of these methods from your property setter.
长话短说,您需要从属性设置器中调用这些方法之一。
Update
更新
As the state of the button is being determined when the active focus is changing, I believe the CommandManager
is being used. So in the setter of your property, after assigning the backing field, invoke CommandManager.InvalidateRequerySuggested()
.
当活动焦点发生变化时,按钮的状态正在确定,我相信CommandManager
正在使用。因此,在您的财产的 setter 中,在分配支持字段后,调用CommandManager.InvalidateRequerySuggested()
.
Update 2
更新 2
The RelayCommand
implementation is from the MVVM light toolkit. When consumed from WPF/.NET, the implementation wraps the methods and events exposed from the CommandManager
. This will mean that these commands work automagically in the majority of situations (where the UI is altered, or the focused element is changed). But in a few cases, such as this one, you will need to manually force the command to re-query. The proper way to do this using this library would be to call the RaiseCanExecuteChanged()
method on the RelayCommand
.
该RelayCommand
实现来自 MVVM light 工具包。当从 WPF/.NET 使用时,实现包装了从CommandManager
. 这意味着这些命令在大多数情况下(UI 更改或焦点元素更改)会自动运行。但是在少数情况下,例如这种情况,您将需要手动强制命令重新查询。正确的方法做到这一点使用这个库将调用RaiseCanExecuteChanged()
的方法RelayCommand
。
回答by Klaus78
You can try with CommandManager.InvalidateRequerySuggested.
您可以尝试使用CommandManager.InvalidateRequerySuggested。
Anyway this did not help me sometimes in the past. For me the best solution turned out to be to bind the boolean property to the Button.IsEnabled
dependency property.
无论如何,这在过去有时对我没有帮助。对我来说,最好的解决方案是将布尔属性绑定到Button.IsEnabled
依赖属性。
In your case something like
在你的情况下类似
IsEnabled={Binding IsTestrunInProgress}
回答by Heliac
This is so important and easy to miss, I am repeating what @Samir said in a comment. Mr Laurent Bugnion wrote in his blog:
这非常重要且容易错过,我在重复@Samir 在评论中所说的话。Laurent Bugnion 先生在他的博客中写道:
In WPF 4 and WPF 4.5, however, there is a catch: The CommandManager will stop working after you upgrade MVVM Light to V5. What you will observe is that your UI elements (buttons, etc) will stop getting disabled/enabled when the RelayCommand's CanExecute delegate returns false.
但是,在 WPF 4 和 WPF 4.5 中,有一个问题:将 MVVM Light 升级到 V5 后,CommandManager 将停止工作。您将观察到的是,当 RelayCommand 的 CanExecute 委托返回 false 时,您的 UI 元素(按钮等)将停止禁用/启用。
If you are in a hurry, here is the fix: In any class that uses the RelayCommand, replace the line saying:
如果您赶时间,这里是修复方法:在任何使用 RelayCommand 的类中,替换以下行:
using GalaSoft.MvvmLight.Command;
with:
和:
using GalaSoft.MvvmLight.CommandWpf;
回答by Amit Kumar
The issue is, the ICommand Property TestrunStartCommand is always returning a new command object whenever it is accessed.
问题是,每当访问 ICommand 属性 TestrunStartCommand 时,它总是返回一个新的命令对象。
A simple fix is to create the ICommand object once and use it again and again.
一个简单的解决方法是创建一次 ICommand 对象并一次又一次地使用它。
private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
get
{
return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress));
}
}
This was quite a simple fix and it worked for me.
这是一个非常简单的修复,它对我有用。