web-dev-qa-db-ja.com

WPFコマンドの更新

カスタムコマンド(Josh Smithの CanExecute )でRelayCommandを強制的に呼び出す方法を知っている人はいますか?

通常、CanExecuteは、UIで対話が発生するたびに呼び出されます。何かをクリックすると、コマンドが更新されます。

舞台裏でタイマーによってCanExecuteの条件がオン/オフになる状況があります。これはユーザーの操作ではないため、ユーザーがUIを操作するまでCanExecuteは呼び出されません。最終結果は、ユーザーがクリックするまでButtonが有効/無効のままになります。クリック後、正しく更新されます。 Buttonは有効になっているように見える場合がありますが、ユーザーがクリックすると、起動ではなく無効に変わります。

タイマーがCanExecuteに影響するプロパティを変更したときに、コードの更新を強制するにはどうすればよいですか? PropertyChangedに影響するプロパティでINotifyPropertyChangedCanExecute)を実行しようとしましたが、助けにはなりませんでした。

XAMLの例:

<Button Content="Button" Command="{Binding Cmd}"/>

背後のコード例:

private ICommand m_cmd;
public ICommand Cmd
{
    if (m_cmd == null)
        m_cmd = new RelayCommand(
            (param) => Process(),
            (param) => EnableButton);

    return m_cmd;
}

// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
69
Josh G
101
Kent Boogaart

私はずっと前にCommandManager.InvalidateRequerySuggested()を知っていて、それを使用しましたが、それは時々私にとってはうまくいきませんでした。私はついにこれが事実である理由を見つけました!他のアクションのようにスローされない場合でも、メインスレッドで呼び出す必要があります。

バックグラウンドスレッドで呼び出すと動作するように見えますが、UIが無効のままになることもあります。これが誰かの助けになり、無駄にした時間を節約できることを本当に願っています。

28
SilverSideDown

そのための回避策は、IsEnabledをプロパティにバインドすることです。

<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>

次に、このプロパティをViewModelに実装します。これにより、UnitTestingがコマンドよりもプロパティを操作しやすくなり、特定の時点でコマンドを実行できるかどうかを確認できます。

個人的には、より便利だと思います。

17
tridy.net

おそらくこのバリアントはあなたに合っています:

 public interface IRelayCommand : ICommand
{
    void UpdateCanExecuteState();
}

実装:

 public class RelayCommand : IRelayCommand
{
    public event EventHandler CanExecuteChanged;


    readonly Predicate<Object> _canExecute = null;
    readonly Action<Object> _executeAction = null;

   public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
    {
        _canExecute = canExecute;
        _executeAction = executeAction;
    }


    public bool CanExecute(object parameter)
    {
       if (_canExecute != null)
            return _canExecute(parameter);
        return true;
    }

    public void UpdateCanExecuteState()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, new EventArgs());
    }



    public void Execute(object parameter)
    {
        if (_executeAction != null)
            _executeAction(parameter);
        UpdateCanExecuteState();
    }
}

シンプルな使用:

public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);

 protected override bool CanEditCommandExecuted(object obj)
    {
        return SelectedItem != null ;
    }

    protected override void EditCommandExecuted(object obj)
    {
        // Do something
    }

   ...

    public TEntity SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;

            //Refresh can execute
            EditCommand.UpdateCanExecuteState();

            RaisePropertyChanged(() => SelectedItem);
        }
    }

XAML:

<Button Content="Edit" Command="{Binding EditCommand}"/>
6
R.Titov

ヒントをありがとう。 BGスレッドからUIスレッドへの呼び出しをマーシャリングする方法に関するコードを次に示します。

private SynchronizationContext syncCtx; // member variable

コンストラクター内:

syncCtx = SynchronizationContext.Current;

バックグラウンドスレッドで、再クエリをトリガーするには:

syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );

お役に立てば幸いです。

-マイケル

4
Michael Kennedy

単一のGalaSoft.MvvmLight.CommandWpf.RelayCommandのみを更新するには、使用できます

mycommand.RaiseCanExecuteChanged();

そして私のために拡張メソッドを作成しました:

public static class ExtensionMethods
    {
        public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
        }

        public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
        }
    }
0
Apfelkuacha