WPF-コマンドにそのCommandBindingsを介して「CanExecute」を再評価させる方法


130

私が持っているMenuそれぞれの場所MenuItemの階層では、その持っているCommandにプロパティセットをRoutedCommand私が定義されてきました。関連付けられたCommandBindingは、CanExecute各の有効状態を制御する評価のコールバックを提供しますMenuItem

これはほとんど機能します。メニュー項目は、最初は正しい有効と無効の状態で表示されます。ただし、CanExecuteコールバックが使用するデータが変更された場合、この新しい状態をUIに反映させるために、コールバックからの結果を再要求するコマンドが必要です。

これに関する、RoutedCommandまたはCommandBindingこれに関するパブリックメソッドはないようです。

コントロールをクリックまたは入力すると、コールバックが再び使用されることに注意してください(マウスオーバーでは更新が発生しないため、入力時にトリガーされると思います)。

回答:


172

本の中で最もきれいではありませんが、CommandManagerを使用してすべてのコマンドバインディングを無効にすることができます。

CommandManager.InvalidateRequerySuggested();

MSDNで詳細を確認する


1
おかげでこれはうまくいきました。UIには少し遅れがありますが、それほど心配はしていません。また、私はすぐにあなたの回答に賛成票を投じ、それからそれが機能するかどうかを確かめるために投票を取り戻しました。現在は機能しているため、投票を再度適用することはできません。SOがそのルールを採用している理由がわかりません。
Drew Noakes、

5
私の投票を再適用するために、あなたの回答を編集しました。編集では何も変更していません。再度、感謝します。
Drew Noakes、

Texboxのコンテンツをコードビハインドから変更しているときにも同じ問題が発生しました。手で編集すればうまくいきます。このアプリでは、ポップアップするコントロールによってtexboxが編集されており、ポップアップを保存すると、Texbox.Textプロパティが変更されます。これで問題は解決しました!ありがとう@Arcturus
Dzyann

10
他の回答(stackoverflow.com/questions/783104/refresh-wpf-command)から「UIスレッドで呼び出さなければならない」に注意してください
Samvel Siradeghyan

84

後でこれに遭遇した人のために; MVVMとPrismをたまたま使用している場合、PrismののDelegateCommand実装ICommandは、.RaiseCanExecuteChanged()これを行う方法を提供します。


12
このパターンは、MVVM Lightなどの他のMVVMライブラリにも見られます。
Peter Lillevold、2011年

2
Prismとは異なり、MVVM Light v5のソースコードは、RaiseCanExecuteChanged() 単に呼び出すことを示しますCommandManager.InvalidateRequerySuggested()
ピーター

4
WPFでのMVVM Lightの補足として、GalaSoft.MvvmLight.Commandが問題を引き起こすため、名前空間GalaSoft.MvvmLight.CommandWpfを使用する必要がありますmvvmlight.net/installing/changes#v5_0_2
fuchs777

((RelayCommand)MyCommand).RaiseCanExecuteChanged();GalaSoft.MvvmLight.Commandを使用して私のために働きました-しかしに変更した後CommandWPF、何も呼び出す必要なしにそれは働きました ありがとう@ fuchs777
ロビンベネット

1
ただし、サードパーティのライブラリを使用していない場合はどうなりますか?
ビダー

28

CommandManager.InvalidateRequerySuggested();パフォーマンスに影響を受けていたため、使用できませんでした。

以下のようなMVVM HelperのDelegatingコマンドを使用しました(reqを少し調整しました)。command.RaiseCanExecuteChanged()VM から呼び出す必要があります

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

/// <summary>
/// This method can be used to raise the CanExecuteChanged handler.
/// This will force WPF to re-query the status of this command directly.
/// </summary>
public void RaiseCanExecuteChanged()
{
    if (canExecute != null)
        OnCanExecuteChanged();
}

/// <summary>
/// This method is used to walk the delegate chain and well WPF that
/// our command execution status has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
    EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
    if (eCanExecuteChanged != null)
        eCanExecuteChanged(this, EventArgs.Empty);
}

3
参考までに、私はCommandManager.RequerySuggested + =値をコメントアウトしました。なんらかの理由でCanExecuteコードのほぼ定数/ループ評価を取得していました。それ以外の場合、ソリューションは期待どおりに機能しました。ありがとう!
robaudas

15

実装する独自のクラスをロールした場合ICommand、自動ステータス更新の多くを失う可能性があり、必要以上に手動の更新に頼らざるを得なくなります。壊れることもありInvalidateRequerySuggested()ます。問題は、単純なICommand実装が新しいコマンドをにリンクできないことCommandManagerです。

解決策は以下を使用することです:

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

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

このようにして、サブスクライバーはCommandManagerクラスではなくにアタッチし、コマンドステータスの変更に適切に参加できます。


2
単純明快で、人々は自分のICommand実装を制御できます。
Akoi Meexx

2

コマンドへのプロパティの依存関係を処理するソリューションを実装しました。ここではリンクhttps://stackoverflow.com/a/30394333/1716620

そのおかげで、次のようなコマンドが作成されます。

this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
    //execute
    () => {
      Console.Write("EXECUTED");
    },
    //can execute
    () => {
      Console.Write("Checking Validity");
       return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
    },
    //properties to watch
    (p) => new { p.PropertyX, p.PropertyY }
 );

-3

これは私にとってうまくいきました:XAMLでコマンドの前にCanExecuteを置きます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.