47

次のようなコマンドにバインドされたボタンを表示するWPF アプリケーションを取得しました。

<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">

コマンドは次のように定義されます。

public ICommand TestrunStartCommand
{
    get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); }
}

public bool IsTestrunInProgress
{
    get{
        return _isTestrunInProgress;
    }
    set{
        _isTestrunInProgress = value;
        RaisePropertyChanged(IsTestrunInProgressPropertyName);
    }
}   

IsTestrunInProgress問題は、 falseに設定した直後にボタンが有効にならず、アプリケーション ウィンドウ内をクリックした後にのみ有効になることです。

この動作を理解し、修正する方法を教えていただけませんか?

さらに読む: wpfコマンドパターン - いつクエリを実行できますか

4

6 に答える 6

61

インターフェイスは、コマンド駆動型 UI コンポーネントの状態をいつ再決定するかを UI に通知するために使用されるICommandイベントを公開します。ICommand.CanExecuteChangedIsEnabled

使用している の実装によっては、RelayCommandこのイベントを発生させる必要がある場合があります。RelayCommand.RaiseCanExecuteChanged()多くの実装では、UI を強制的に更新するために呼び出すことができるメソッドなどを公開しています。

RelayCommandを利用する 一部の実装では、UI を強制的に更新するためCommandManager.RequerySuggestedに を呼び出す必要があります。CommandManager.InvalidateRequerySuggested()

簡単に言うと、プロパティ セッターからこれらのメソッドのいずれかを呼び出す必要があります。

アップデート

アクティブ フォーカスが変更されたときにボタンの状態が決定されるため、CommandManagerが使用されていると思います。したがって、プロパティのセッターで、バッキング フィールドを割り当てた後、 を呼び出しCommandManager.InvalidateRequerySuggested()ます。

更新 2

RelayCommand実装は、MVVM ライト ツールキットからのものです。WPF/.NET から使用されると、実装は .NET から公開されたメソッドとイベントをラップしますCommandManager。これは、ほとんどの状況 (UI が変更されたり、フォーカスされた要素が変更されたりした場合) で、これらのコマンドが自動的に機能することを意味します。ただし、このようないくつかのケースでは、コマンドを手動で強制的に再クエリする必要があります。このライブラリを使用してこれを行う適切な方法は、 でRaiseCanExecuteChanged()メソッドを呼び出すことRelayCommandです。

于 2013-01-23T12:12:32.163 に答える
5

CommandManager.InvalidateRequerySuggestedで試すことができます。

とにかく、これは過去に時々私を助けませんでした。Button.IsEnabled私にとって最善の解決策は、ブール値プロパティを依存関係プロパティにバインドすることであることが判明しました。

あなたの場合、次のようなもの

IsEnabled={Binding IsTestrunInProgress}
于 2013-01-23T12:13:02.580 に答える
0

上記の Riegardt Steyn の回答への追加: https://stackoverflow.com/a/33503341/1964969

Command使用法を変更したくない場合CommandWpf(2 つの RelayCommand バージョン間で互換性がないため)、別の回避策として、宣言の場所でコマンドをインスタンス化しないこともできます。代わりにコンストラクター コードを使用します。

public class SomeVMClass
{
    // CanExecute won't work:
    // Declaration and instantiation same place
    public RelayCommand MyCommand1 => new RelayCommand(MyBusinessLogic, MyCanExecuteValidator);

    // CanExecute will work
    // Declaration only
    public RelayCommand MyCommand2 { get; private set; }

    public SomeVMClass()
    {
        // Let's instantiate our declared command
        MyCommand2 = new RelayCommand(MyBusinessLogic, MyCanExecuteValidator);
       ...
于 2021-09-15T11:12:31.120 に答える
0

問題は、アクセスされるたびに ICommand プロパティ TestrunStartCommand が常に新しいコマンド オブジェクトを返すことです。

簡単な修正方法は、ICommand オブジェクトを一度作成し、それを何度も使用することです。

private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
    get 
    { 
        return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress)); 
    }
}

これは非常に簡単な修正であり、私にとってはうまくいきました。

于 2017-12-24T23:04:46.110 に答える