繁体   English   中英

如何强制更新MVVM中的UI?

[英]How can I force update of the UI in MVVM?

好吧,让我试着解释一下。

我有一个应用程序,我可以触发某种扫描过程。 这个扫描过程启动(只有很多)10个后台工作人员做某事。 之后(再次,只是一个数字)5秒我想

  • 杀死所有后台工作人员(我正在使用CancelAsync)
  • 用我从他们所有的数据做一些计算
  • 更新用户界面,使得显示的数据,并启用一些按钮(这些按钮是通过绑定ViewModel命令调用PerformUpdateCommand ,他们有一个CanExecute财产IsPerformUpdateAllowedIsPerformUpdateAllowed时,我的任务完成依赖属性设置。

我以为我会做什么:

  • 触发后台工作程序后,启动一个间隔为5秒的调度程序计时器。
  • DispatcherTimer “ticks”时,我计算数据并将属性IsPerformUpdateAllowed设置为true或false。

这基本上按预期工作(UI保持响应,......),只需要一个小小的hickup:UI没有被更新(按钮未启用)。 只要我将窗口置于后台并返回到前台,就会启用该命令,同时IsPerformUpdateAllowed属性也会设置为true。 此外,按下按钮后按下按钮(处于禁用状态),将启用该按钮。

因此,虽然我正确设置了依赖项属性,但UI不会对此更改做出反应。

谁知道为什么? 有趣的是,我还在UI中将一些文本设置为标签 - 此文本已正确更新。 只是告诉命令CanExecute的属性不会触发UI更新。

用于初始化定时器的代码。

        _scanTimer = new DispatcherTimer();
        _scanTimer.Interval = new TimeSpan(0, 0, 0, 3);
        _scanTimer.Tick += delegate
        {
            // After the timer has elapsed (some time passed), cancel all scans and update the result
            _scanTimer.Stop();
            UpdateScanResults();
            CancelNormalScans(false);
        };
        _scanTimer.Start();

编码命令如何绑定到WPF元素(该按钮实际上是一个超链接):

            <Label Grid.Row="1" Grid.Column="1">
                <Hyperlink Command="{Binding ReadSettingsCommand}">
                    <TextBlock Text="{Binding Source={StaticResource Loc}, Path=Labels.ReadSettings}"></TextBlock>
                </Hyperlink>
            </Label>

这是Command的代码

    public RelayCommand ReadSettingsCommand
    {
        get
        {
            return _readSettingsCommand
                ?? (_readSettingsCommand = new RelayCommand(ExecuteReadSettings, () => IsScannedDeviceAvailable && !IsUpdateInProgress));
        }
    }

代码实际上依赖于两个依赖属性IsScannedDeviceAvailable AND NOT IsUpdateInProgress。 两者都是依赖属性。

更新:我刚刚读到,对CanExecute属性的绑定只是一次。 如果要重新验证,则需要在命令上调用RaiseCanExecuteChanged。 这可行,但它有点麻烦,因为现在每次两个属性中的一个更改时我需要手动调用它。 实际上我希望自动处理。 关于如何更容易地做到这一点的任何想法? 是不是有一些方法可以在CanExecute和属性之间进行单向绑定?

每当设置IsScannedDeviceAvailable / IsUpdateInProgress时,在VM上调用RaiseCanExecuteChanged。 或者我个人最喜欢创建自己的ICommand实现,因为它非常简单。

public class FooCommand : ICommand
{
    private bool _canExecute;
    private Action _delegate;
    public event EventHandler CanExecuteChanged;
    public new bool CanExecute
    {
        get
        {
            return _canExecute;
        }
        set
        {
            _canExecute = value;
            if(CanExecuteChanged != null)
                CanExecuteChanged();
        }
    }

    public void Execute(object parameter)
    {
        _delegate();
    }

    bool ICommand.CanExecute()
    {
        return CanExecute;
    }

    public FooCommand(Action action)
    {
        _delegate = action;
    }
}

如果基于属性触发Command.CanExecute()的更改,还可以调用CommandManager.InvalidateRequerySuggested()来强制重新评估CanExecute()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM