1

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

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

  • 杀死所有后台工作人员(我为此使用 CancelAsync)
  • 用我从他们那里得到的数据做一些计算
  • 更新 UI 以便显示数据并启用一些按钮(这些按钮通过ViewModel调用的命令绑定,PerformUpdateCommand并且它们具有.CanExecute属性IsPerformUpdateAllowedIsPerformUpdateAllowed当我的任务完成时设置依赖属性。

我想我会做什么:

  • 触发后台工作人员后,以 5 秒的间隔启动调度程序计时器。
  • DispatcherTimer“滴答声”时,我计算数据并将属性设置IsPerformUpdateAllowed为真或假。

这基本上可以按预期工作(UI 保持响应,...),只是一个小问题: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>

这是命令的代码

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

该代码实际上依赖于两个依赖属性 IsScannedDeviceAvailable 而不是 IsUpdateInProgress。两者都是依赖属性。

更新:我刚刚读到与 CanExecute 属性的绑定只是一次。如果您希望它重新验证,您需要在命令上调用 RaiseCanExecuteChanged。这可行,但有点麻烦,因为现在我需要在每次两个属性之一更改时手动调用它。实际上我希望自动处理它。关于如何更轻松地完成此操作的任何想法?难道没有某种方法可以在 CanExecute 和属性之间建立一种单向绑定吗?

4

2 回答 2

3

每当设置 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;
    }
}
于 2013-11-04T08:48:23.903 回答
1

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

于 2014-07-16T08:23:01.827 回答