我得到了一个WPF应用程序,它显示了一个绑定到命令的按钮:
<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">
命令的定义如下:
public ICommand TestrunStartCommand
{
get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); }
}
public bool IsTestrunInProgress
{
get{
return _isTestrunInProgress;
}
set{
_isTestrunInProgress = value;
RaisePropertyChanged(IsTestrunInProgressPropertyName);
}
}
问题是,在我将IsTestrunInProgress
设置为false后,该按钮不会立即启用,而是 * 只有在我在应用程序窗口内单击 * 后才启用。
你能帮助我理解这种行为并告诉我如何解决这个问题吗?
7条答案
按热度按时间wtzytmuj1#
ICommand
接口公开了一个事件ICommand.CanExecuteChanged
,用于通知UI何时重新确定命令驱动UI组件的IsEnabled
状态。根据您正在使用的
RelayCommand
的实现,您可能需要引发此事件;许多实现都公开了一个方法,如RelayCommand.RaiseCanExecuteChanged()
,您可以调用它来强制刷新UI。RelayCommand
的一些实现使用CommandManager.RequerySuggested
,在这种情况下,您需要调用CommandManager.InvalidateRequerySuggested()
来强制刷新UI。长话短说,您需要从属性设置器调用这些方法之一。
更新
由于按钮的状态正在确定时,活动焦点正在改变,我相信正在使用的
CommandManager
。因此,在属性的setter中,在分配了backing字段之后,调用CommandManager.InvalidateRequerySuggested()
。更新2
RelayCommand
的实现来自MVVM light工具包。当从WPF/.NET使用时,实现 Package 了从CommandManager
公开的方法和事件。这将意味着这些命令在大多数情况下(UI被更改,或者焦点元素被更改)自动工作。但在少数情况下,例如本例,您需要手动强制命令重新查询。使用此库实现此目的的正确方法是在RelayCommand
上调用RaiseCanExecuteChanged()
方法。hjzp0vay2#
这是如此重要和容易错过,我在重复@Samir在评论中所说的话。Laurent Bugnion先生在他的blog中写道:
qvsjd97n3#
你可以试试CommandManager.InvalidateRequerySuggested。
不管怎么说,这在过去有时并没有帮助我。对我来说,最好的解决方案是将boolean属性绑定到
Button.IsEnabled
依赖属性。在你的情况下
nbysray54#
问题是,每当访问ICommandProperty TestrunStartCommand时,它总是返回新的命令对象。
一个简单的解决方法是创建ICommand对象一次,然后反复使用它。
这是一个相当简单的修复和它为我工作。
gr8qqesn5#
对Riegardt Steyn上述回答的补充:https://stackoverflow.com/a/33503341/1964969
如果不想将
Command
的用法更改为CommandWpf
(因为两个RelayCommand版本之间不兼容),另一种解决方法是不在声明位置示例化命令。使用构造函数代码代替:kyks70gy6#
Blockquote
在Command类中将CanExecutedChanged更改为
这是我的命令类的例子
7fyelxc57#
如果你使用的是
BackgroundWorker
(不一定是OP要求的),CommandManager.InvalidateRequerySuggested()
只会在ProgressChanged
回调中工作,而不会在DoWork
回调中工作。