C# ICommand是否可以在属性更改后执行不触发?
我得到了一个WPF应用程序,它显示了一个绑定到如下命令的按钮:C# ICommand是否可以在属性更改后执行不触发?,c#,wpf,mvvm-light,C#,Wpf,Mvvm Light,我得到了一个WPF应用程序,它显示了一个绑定到如下命令的按钮: <Button Command="{Binding Path=TestrunStartCommand}" Content="GO!"> public ICommand TestrunStartCommand { get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); } } public bool I
<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后,该按钮不会立即启用,而只能在我在应用程序窗口内单击后启用
你能帮我理解这种行为,并告诉我如何解决这个问题吗
进一步阅读:
接口
ICommand
会公开一个事件,用于通知UI何时重新确定命令驱动UI组件的IsEnabled
状态
根据您正在使用的RelayCommand
的实现情况,您可能需要引发此事件;许多实现公开了一种方法,例如RelayCommand.raiseCanceTechChanged()
,您可以调用该方法来强制UI刷新
RelayCommand
的一些实现利用了,在这种情况下,您需要调用以强制UI刷新
长话短说,您将需要从属性设置程序调用其中一个方法
更新
当活动焦点改变时,按钮的状态正在确定,我相信正在使用CommandManager
。因此,在属性的setter中,在分配了backing字段之后,调用
更新2
RelayCommand
实现来自MVVM light toolkit。当从WPF/.NET使用时,实现会包装从CommandManager
公开的方法和事件。这将意味着这些命令在大多数情况下自动工作(用户界面被改变,或者焦点元素被改变)。但是在一些情况下,例如在本例中,您需要手动强制命令重新查询。使用此库执行此操作的正确方法是调用您可以尝试使用的RelayCommand
上的raisecancecutechanged()
方法
不管怎么说,这在过去有时对我没有帮助。对我来说,最好的解决方案是将布尔属性绑定到按钮
就你的情况来说
IsEnabled={Binding IsTestrunInProgress}
这很重要,很容易错过,我重复@Samir在评论中说的话。Laurent Bugnon先生在他的报告中写道:
然而,在WPF4和WPF4.5中,有一个陷阱:将MVVMLight升级到V5后,CommandManager将停止工作。您将观察到,当RelayCommand的CanExecute委托返回false时,UI元素(按钮等)将停止禁用/启用
如果您赶时间,这里有一个解决方案:在任何使用RelayCommand的类中,替换以下行:
与:
问题是,每当访问ICommand属性TestrunStartCommand时,它总是返回一个新的命令对象
一个简单的修复方法是创建ICommand对象一次,然后反复使用它
private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
get
{
return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress));
}
}
这是一个非常简单的修复程序,对我来说很有效。只有在我在应用程序窗口中单击后才生效;您是否暗示操作系统中当前活动的窗口不是此程序窗口?或者换句话说,此应用程序已启动并正在运行,但您在记事本中,只能在后台看到窗口。@MichaelPerrenoud:不,应用程序窗口处于活动状态并具有焦点。似乎只有在我的窗口内单击时才会计算CanExecuteChanged
。Galasoft库中的RelayCommand有效effeciently@HichemC我确信它能有效地工作,错误当然在我(初学者)这一边。但是我的错误在哪里?你是对的:我在我的RelayCommand
中得到了raisecanextechanged
方法。但我不明白的是,我有很多工作按钮,我从来没有手动启动过这个事件,不知何故,它的工作方式就像魔术一样。在这种情况下有什么不同?我认为这个谜题中仍然缺少一些东西……所有这些按钮都使用了相同的RelayCommand
?您能告诉我您使用的是哪种实现吗?i、 e.该类来自哪个库?是,所有按钮使用相同的RelayCommand
。我正在使用。如果使用WPF 4.5或更高版本,则需要使用命名空间GalaSoft.MvvmLight.CommandWpf中的RelayCommand,而不是GalaSoft.MvvmLight.Command。这将重新启用RelayCommand以使用CommandManager。我注意到另一件重要的事情,如果您从非UI线程设置(引起更改的)属性,则需要通过Dispatcher调用上述方法。否则,WPF会吞下通知。是的,像您所说的那样使用绑定,它就像一个符咒一样工作。这首先会破坏使用命令的目的,并且只有在您的启用状态依赖于单个属性时才起作用。非常感谢。。你救了我的周末:)天哪!我在这上面浪费了太多时间,通常我喜欢Mvvm灯,但不是今天。哦,天哪。现在是2020年,距离最初的答案已经5年了,我刚刚花了两个小时的大部分时间试图弄清楚为什么这在一个视图/视图模型中不起作用,但在另一个视图/视图模型中起作用。。。两个命令代码完全相同。。。除了一个使用了GalaSoft.MvvmLight.Command
而不是GalaSoft.MvvmLight.CommandWpf
。。。天哪,这太令人沮丧了。
using GalaSoft.MvvmLight.CommandWpf;
private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
get
{
return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress));
}
}