4

最近、Windows 8 Release Preview (具体的にはビルド 8400) を少し試す機会がありました。私の目的は、私たちの製品 (WPF アプリケーション) に Windows 8 でのみ発生したバグを調査することでした。バグは非常に単純に見えました。修正するのは簡単に見えましたが、根本的な原因を見つけることにしました。

コマンドにバインドされたコントロールが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;
  }

現在、送信者はコマンド自体であり、すべて問題ありません。別のオプションはCommandManager、そのRequerySuggestedイベントを使用することです:

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

そして再びそれは機能します!うーん、今、私は完全に困惑しています。Sender はコマンドではありません - null ですが、null の送信者で自分のイベントを送信しようとすると、再び機能しません。

誰かが同じに直面しましたか?新しい Windows での最適化の奇妙な方法ですか? 正直なところ、それはバグのように見えます。

4

1 に答える 1

4

どうやら、これは.NetFramework4.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 に答える