71

したがって、私が行っているこの特定のMVVM実装では、いくつかのコマンドが必要です。ICommandクラスを1つずつ実装するのに本当にうんざりしていたので、解決策を考え出しましたが、それがどれほど優れているかわからないので、ここでのWPFエキスパートの意見をいただければ幸いです。そして、あなたがより良い解決策を提供できれば、さらに良いでしょう。

私が行ったのは、単一のICommandクラスと、オブジェクトをパラメーターとして受け取る2つのデリゲートです。1つのデリゲートはvoid(OnExecuteの場合)、もう1つのデリゲートは(OnCanExecuteの場合)です。したがって、ICommandのコンストラクター(ViewModelクラスによって呼び出されます)で2つのメソッドを送信し、各ICommandメソッドでデリゲートのメソッドを呼び出します。

それは本当にうまくいきますが、これがそれを行うのに悪い方法なのか、それとももっと良い方法があるのか​​はわかりません。以下は完全なコードです。否定的であっても、どんな入力でも大歓迎ですが、建設的にしてください。

ViewModel:

public class TestViewModel : DependencyObject
{
    public ICommand Command1 { get; set; }
    public ICommand Command2 { get; set; }
    public ICommand Command3 { get; set; }

    public TestViewModel()
    {
        this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1);
        this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2);
        this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3);
    }

    public bool CanExecuteCommand1(object parameter)
    {
        return true;
    }

    public void ExecuteCommand1(object parameter)
    {
        MessageBox.Show("Executing command 1");
    }

    public bool CanExecuteCommand2(object parameter)
    {
        return true;
    }

    public void ExecuteCommand2(object parameter)
    {
        MessageBox.Show("Executing command 2");
    }

    public bool CanExecuteCommand3(object parameter)
    {
        return true;
    }

    public void ExecuteCommand3(object parameter)
    {
        MessageBox.Show("Executing command 3");
    }
}

ICommand:

public class TestCommand : ICommand
{
    public delegate void ICommandOnExecute(object parameter);
    public delegate bool ICommandOnCanExecute(object parameter);

    private ICommandOnExecute _execute;
    private ICommandOnCanExecute _canExecute;

    public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
    {
        _execute = onExecuteMethod;
        _canExecute = onCanExecuteMethod;
    }

    #region ICommand Members

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

    public bool CanExecute(object parameter)
    {
        return _canExecute.Invoke(parameter);
    }

    public void Execute(object parameter)
    {
        _execute.Invoke(parameter);
    }

    #endregion
}
4

4 に答える 4

88

これは、KarlShiffletが事前に決められたを発射する方法を示した方法とほぼ同じです。あなたが私に尋ねれば、一流の解決策。RelayCommandExecuteAction<T>

public class RelayCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }

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

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

これは、次のように使用できます...

public class MyViewModel
{
    private ICommand _doSomething;
    public ICommand DoSomethingCommand
    {
        get
        {
            if (_doSomething == null)
            {
                _doSomething = new RelayCommand(
                    p => this.CanDoSomething,
                    p => this.DoSomeImportantMethod());
            }
            return _doSomething;
        }
    }
}

続きを読む:
Josh Smith(の紹介者RelayCommand):パターン-MVVMデザインパターンを使用したWPFアプリ

于 2009-09-23T22:19:03.237 に答える
17

ICommandインターフェースについてこの記事を書きました。

アイデア-2つのデリゲートを受け取るユニバーサルコマンドを作成します。1つはが呼び出されたときICommand.Execute (object param)に呼び出され、もう1つはコマンドを実行できるかどうかのステータスをチェックします(ICommand.CanExecute (object param))

イベントを切り替えるメソッドが必要CanExecuteChangedです。CanExecute()これは、stateコマンドを切り替えるためにユーザーインターフェイス要素から呼び出されます。

public class ModelCommand : ICommand
{
    #region Constructors

    public ModelCommand(Action<object> execute)
        : this(execute, null) { }

    public ModelCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion

    #region ICommand Members

    public event EventHandler CanExecuteChanged;

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

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

    public void OnCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }

    #endregion

    private readonly Action<object> _execute = null;
    private readonly Predicate<object> _canExecute = null;
}
于 2011-04-08T19:14:31.387 に答える
10

設定より規約でコマンドを実装する方法を示す小さな例を作成しました。ただし、Reflection.Emit()を使用できるようにする必要があります。サポートコードは少し奇妙に見えるかもしれませんが、一度書かれると何度も使用できます。

ティーザー:

public class SampleViewModel: BaseViewModelStub
{
    public string Name { get; set; }

    [UiCommand]
    public void HelloWorld()
    {
        MessageBox.Show("Hello World!");
    }

    [UiCommand]
    public void Print()
    {
        MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel");
    }

    public bool CanPrint()
    {
        return !String.IsNullOrEmpty(Name);
    }
}

}

更新:現在、ICommandボイラープレートコードの問題を解決するhttp://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Modelのようないくつかのライブラリが存在するようです。

于 2010-01-01T17:08:06.827 に答える
6

@Carlo私はこれの実装が本当に好きですが、私のバージョンとそれをViewModelで使用する方法を共有したいと思いました

最初にICommandを実装します

public class Command : ICommand
{
    public delegate void ICommandOnExecute();
    public delegate bool ICommandOnCanExecute();

    private ICommandOnExecute _execute;
    private ICommandOnCanExecute _canExecute;

    public Command(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod = null)
    {
        _execute = onExecuteMethod;
        _canExecute = onCanExecuteMethod;
    }

    #region ICommand Members

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

    public bool CanExecute(object parameter)
    {
        return _canExecute?.Invoke() ?? true;
    }

    public void Execute(object parameter)
    {
        _execute?.Invoke();
    }

    #endregion
}

ICommandOnExecuteおよびICommandOnCanExecuteからパラメーターを削除し、コンストラクターにnullを追加したことに注意してください。

次に、ViewModelで使用します

public Command CommandToRun_WithCheck
{
    get
    {
        return new Command(() =>
        {
            // Code to run
        }, () =>
        {
            // Code to check to see if we can run 
            // Return true or false
        });
    }
}

public Command CommandToRun_NoCheck
{
    get
    {
        return new Command(() =>
        {
            // Code to run
        });
    }
}

変数を割り当ててからインスタンス化する必要がないので、この方法がすっきりします。すべてを一度に実行できます。

于 2017-11-08T22:13:58.207 に答える