4

最近我有机会玩一点 Windows 8 Release Preview(具体来说是 Build 8400)。我的目标是调查仅在 Windows 8 下出现在我们的产品(WPF 应用程序)中的错误。错误看起来非常简单 - 一些按钮在不应该被禁用时被禁用。它看起来很容易修复,但我决定找到根本原因。

事实证明,当绑定到命令的控件接收到通知时,如果发送者不是同一个命令CanExecuteChanged,它不会重新查询命令的方法。CanExecute当命令对模型执行某些操作并且它的执行能力取决于模型的状态时,这有点问题。例如,假设您有一个模型:

class MyModel
  {
    public void ChangeModel(bool makeValidForCommand)
    {
      Valid = makeValidForCommand;

      if (ModelChanged != null)
        ModelChanged(this, new EventArgs());
    }

    public bool Valid { get; private set; }

    public event EventHandler ModelChanged;
  }

和一个命令:

class MyCommand : ICommand
  {
    public MyCommand(MyModel model)
    {
      _model = model;
    }

    public bool CanExecute(object parameter)
    {
      return _model.Valid;
    }

    public event EventHandler CanExecuteChanged
    {
      add { _model.ModelChanged += value; }
      remove { _model.ModelChanged -= value; }
    }

    public void Execute(object parameter) { }

    private MyModel _model;
  }

不幸的是,这在 Windows 8 上不起作用 - 绑定到命令的按钮将在模型更改状态后保持不正确的禁用(或启用)状态。不过,它在 Windows 7 上运行良好!

该命令可以这样重写:

class MyCommand : ICommand
  {
    public MyCommand(MyModel model)
    {
      _model = model;
    }

    public bool CanExecute(object parameter)
    {
      return _model.Valid;
    }

    public event EventHandler CanExecuteChanged
    {
      add
      {
        _canExecuteChanged += value;
        _model.ModelChanged -= _modelChanged;
        _model.ModelChanged += _modelChanged;
      }

      remove
      {
        _canExecuteChanged -= value;
        _model.ModelChanged -= _modelChanged;
      }
    }

    public void Execute(object parameter)
    {
    }

    private void _modelChanged(object sender, EventArgs e)
    {
      if (_canExecuteChanged != null)
        _canExecuteChanged(this, new EventArgs());
    }

    private event EventHandler _canExecuteChanged;
    private MyModel _model;
  }

现在 sender 是命令本身,一切都很好。另一种选择是使用CommandManager及其RequerySuggested事件:

public event EventHandler CanExecuteChanged
    {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
    }

它再次起作用!嗯,现在我完全迷惑了。Sender 不是命令-它是空的,但是如果我尝试使用空的发件人发送我自己的事件,它就不再起作用了。

有没有人遇到过同样的情况?在新Windows上是不是有这么奇怪的优化方式?老实说,它看起来更像是一个错误。

4

1 回答 1

4

似乎,这是 .Net Framework 4.5 中的一个重大变化。该问题在此处报告给 Microsoft:

http://connect.microsoft.com/VisualStudio/feedback/details/751429/wpf-icommand-canexecutechanged-behaviour-change-in-net-4-5

于 2012-08-27T08:09:50.580 回答