我有一个 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后不会立即启用该按钮,但只有在我单击应用程序窗口之后才会启用。
你能帮助我理解这种行为,并告诉我如何解决这个问题吗?
答案 0 :(得分:48)
ICommand
接口公开了一个事件ICommand.CanExecuteChanged
,用于通知UI何时重新确定命令驱动的UI组件的IsEnabled
状态。
根据您使用的RelayCommand
的实施情况,您可能需要提出此事件;许多实现都公开了一个方法,例如RelayCommand.RaiseCanExecuteChanged()
,您可以调用该方法来强制UI刷新。
RelayCommand
的某些实现使用CommandManager.RequerySuggested
,在这种情况下,您需要调用CommandManager.InvalidateRequerySuggested()
来强制UI刷新。
长话短说,您需要从属性设置器中调用其中一种方法。
<强>更新强>
由于当活动焦点发生变化时确定按钮的状态,我相信正在使用CommandManager
。因此,在您的属性的setter中,在分配支持字段后,调用CommandManager.InvalidateRequerySuggested()
。
更新2
RelayCommand
实现来自MVVM light工具包。从WPF / .NET使用时,实现将包装从CommandManager
公开的方法和事件。这意味着这些命令在大多数情况下(UI被更改,或者焦点元素被更改)自动运行。但在少数情况下,例如这个,你需要手动强制命令重新查询。使用此库执行此操作的正确方法是在RaiseCanExecuteChanged()
上调用RelayCommand
方法。
答案 1 :(得分:44)
这是非常重要且容易错过的,我正在重复@Samir在评论中所说的话。 Laurent Bugnion先生在他的blog中写道:
但是,在WPF 4和WPF 4.5中,有一个问题:在将MVVM Light升级到V5后,CommandManager将停止工作。您将观察到当RelayCommand的CanExecute委托返回false时,您的UI元素(按钮等)将停止被禁用/启用。
如果你赶时间,这里有修复:在任何使用RelayCommand的类中,替换说:
的行using GalaSoft.MvvmLight.Command;
使用:
using GalaSoft.MvvmLight.CommandWpf;
答案 2 :(得分:4)
您可以尝试使用CommandManager.InvalidateRequerySuggested。
无论如何,这对我有时在过去没有帮助。对我来说,最好的解决方案是将布尔属性绑定到Button.IsEnabled
依赖项属性。
在你的情况下像
IsEnabled={Binding IsTestrunInProgress}
答案 3 :(得分:1)
问题是,无论何时访问,ICommand Property TestrunStartCommand都会返回一个新的命令对象。
一个简单的解决方法是创建一次ICommand对象并一次又一次地使用它。
private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
get
{
return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress));
}
}
这是一个非常简单的修复,它对我有用。