WPF - 通过后台工作程序查看模型更新属性,但视图在重点之前不更新某些元素

时间:2011-05-17 03:11:40

标签: wpf mvvm binding backgroundworker mvvm-light

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);
}

2 个答案:

答案 0 :(得分:4)

来自其他thread的答案:

  

当BackgroundWorker完成后,调用CommandManager.InvalidateRequerySuggested();

     

默认情况下,命令仅偶尔由WPF重新获得。否则,在每个ICommand实现上不断调用“CanExecute”会产生大量开销。调用上述方法会强制CommandManager立即更新。

     

这将强制命令重新启用/禁用。

编辑:

我使用更简单但不那么漂亮的解决方法。我只是在我的BackgroundWorker完成事件中为我的命令调用OnPropertyChanged(“MyICommand”)。

编辑:

here是另一个不错的解决方案。

答案 1 :(得分:0)

您应该将命令参数属性绑定到viewmodel上的任何可更新属性,并且可以执行必须使用此命令参数来启用按钮。如果更新了命令参数的目标,则绑定将根据can excute的返回值启用/禁用。