View模型使用模型中的后台工作线程异步加载数据。模型和视图模型中的所有属性都会引发属性更改事件,并且所有属性都在视图中按预期更新,除了 2个按钮,其IsEnabled
状态取决于某些属性的结果已加载。
令人沮丧的是,只要我专注于视图的任何部分,或者在更新属性后设置断点(创建延迟),按钮IsEnabled
状态就会按预期更新。所以这似乎是一个时间问题。
有关如何解决此问题的最佳方法的任何线索?我正在使用mvvm-light框架,但这不重要。
我尝试将IsEnabled
绑定到按钮而不是仅仅依赖Command
属性,但这没有任何区别。我已通过日志记录确认已设置视图模型属性,并且为与按钮关联的属性引发了PropertyChanged
事件。
考虑使用mvvm-light messenger从视图模型向异步已完成事件的视图发送消息然后以某种方式?触发视图刷新,但这似乎是一个kludge。
感谢blindmeis的回答,我测试了没有Command绑定集的按钮行为,即只绑定了IsEnabled属性,它按预期工作!
<Button
Grid.Column="2" Content="{Binding LoadProjectsLabel}"
VerticalAlignment="Top" HorizontalAlignment="Right"
IsEnabled="{Binding CanLoadProjects}" />
显然它不是很好,因为我不能再执行命令:)但是一旦我添加命令,它就会停止行为:
<Button
Grid.Column="2" Content="{Binding LoadProjectsLabel}"
VerticalAlignment="Top" HorizontalAlignment="Right"
Command="{Binding LoadProjectsCommand}" />
离开IsEnabled
绑定并不能解决问题,但这似乎是一个很好的线索。
视图模型命令代码:
public ICommand LoadProjectsCommand
{
get
{
if (_loadProjectsCommand == null)
{
_loadProjectsCommand = new RelayCommand(loadProjects, () => CanLoadProjects);
}
return _loadProjectsCommand;
}
}
结束Click
事件并避免Command
。很高兴从视图模型中解决它,但这可行:
<Button
Grid.Column="2" Content="{Binding LoadProjectsLabel}"
VerticalAlignment="Top" HorizontalAlignment="Right"
IsEnabled="{Binding CanLoadProjects}"
Click="loadProjects_Click"/>
代码背后:
void loadProjects_Click(object sender, RoutedEventArgs e)
{
SettingsViewModel vm = (SettingsViewModel)DataContext;
vm.LoadProjectsCommand.Execute(null);
}
答案 0 :(得分:4)
来自其他thread的答案:
当BackgroundWorker完成后,调用CommandManager.InvalidateRequerySuggested();
默认情况下,命令仅偶尔由WPF重新获得。否则,在每个ICommand实现上不断调用“CanExecute”会产生大量开销。调用上述方法会强制CommandManager立即更新。
这将强制命令重新启用/禁用。
编辑:
我使用更简单但不那么漂亮的解决方法。我只是在我的BackgroundWorker完成事件中为我的命令调用OnPropertyChanged(“MyICommand”)。
编辑:
here是另一个不错的解决方案。
答案 1 :(得分:0)
您应该将命令参数属性绑定到viewmodel上的任何可更新属性,并且可以执行必须使用此命令参数来启用按钮。如果更新了命令参数的目标,则绑定将根据can excute的返回值启用/禁用。