Реализация WPF ICommand MVVM

Поэтому в этой конкретной реализации MVVM, которую я делаю, мне нужно несколько команд. Я действительно устал от внедрения classов ICommand один за другим, поэтому я придумал решение, но я не знаю, насколько это хорошо, поэтому вклад любого эксперта WPF здесь будет очень благодарен. И если бы вы могли обеспечить лучшее решение, еще лучше!

То, что я сделал, это один class ICommand и два делегата, которые принимают объект как параметр, один делегат недействителен (для OnExecute), другой bool (для OnCanExecute). Поэтому в конструкторе моей ICommand (который вызывается classом ViewModel) я отправляю два метода, и по каждому методу 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 } 

Это почти идентично тому, как Карл Шиффлет продемонстрировал RelayCommand , где Execute запускает предопределенное Action . Самое первоclassное решение, если вы спросите меня.

 public class RelayCommand : ICommand { private Predicate _canExecute; private Action _execute; public RelayCommand(Predicate canExecute, Action execute) { this._canExecute = canExecute; this._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; } } } 

Прочитайте больше:
Джош Смит (разработчик RelayCommand ): шаблоны – приложения WPF с шаблоном проектирования MVVM

Я написал эту статью об интерфейсе ICommand.

Идея – создание универсальной команды, которая принимает два делегата: один вызывается при вызове ICommand.Execute (object param) , второй проверяет состояние выполнения команды (ICommand.CanExecute (object param)) .

Требуется метод переключения события CanExecuteChanged . Он вызывается из элементов пользовательского интерфейса для переключения команды CanExecute() .

 public class ModelCommand : ICommand { #region Constructors public ModelCommand(Action execute) : this(execute, null) { } public ModelCommand(Action execute, Predicate 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 _execute = null; private readonly Predicate _canExecute = null; } 

Я только что создал небольшой пример, показывающий, как реализовать команды в условном стиле конфигурации. Однако для этого требуется 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); } } 

}

UPDATE : теперь, похоже, существуют некоторые библиотеки, такие как http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model, которые решают проблему шаблона ICommand.

@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 }); } } 

Я просто нахожу этот способ более чистым, так как мне не нужно назначать переменные, а затем создавать экземпляр, все это делается за один раз.

  • Удалить файл, используемый другим процессом
  • WPF Combobox: различные шаблоны в текстовом поле и выпадающем списке
  • В WPF, каковы различия между атрибутами x: Name и Name?
  • WPF MVVM просматривает просмотры
  • В чем разница между ContentControl и ContentPresenter?
  • Поиск WPF ComboBox с флажками
  • Как Windows 8 Runtime (приложения для WinRT / Windows Store / Windows 10 Universal App) сравниваются с Silverlight и WPF?
  • Как включить виртуализацию пользовательского интерфейса в стандартном WPF ListView
  • Динамически добавлять несколько кнопок в окно wpf?
  • Назначить BitmapImage из Resource.resx в Image.Source?
  • Как я могу программно генерировать события нажатия клавиш на C #?
  • Давайте будем гением компьютера.