Альтернатива MVVM ICommand

Я начал создавать приложение wpf mvvm. Кажется, что жизненно важным ингредиентом ViewModel является набор ICommands, которые имеют слабосвязанный способ, позволяющий представлению взаимодействовать с viewmodel.

Мой вопрос в том, почему я не могу напрямую привязаться к методу?

Я использовал реализацию ICommand Джоша Смита RelayCommand, которая позволяет вам вводить delgates в объект ICommand, но на самом деле, есть ли более простой способ разрешить нажатие кнопки для вызова метода в модели представления?

Я новичок в MVVM, я считаю, что мне нужно немного просвещения


person Jose    schedule 29.05.2009    source источник
comment
Вы можете привязать к методу: ‹Button Click = YouEventHandlerMethod /› ... Но вы, вероятно, хотите объединить логику включения / выключения и логику выполнения вместе? Вот почему вам нужна команда.   -  person Lex Lavnikov    schedule 29.11.2010


Ответы (5)


Вы не можете выполнить привязку напрямую к методу, потому что Button (например) не имеет свойства, которое принимает делегат. Вместо этого у него есть свойство Command типа ICommand. RelayCommand (он же DelegateCommand) - это просто ICommand, который обертывает делегатов.

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

<Button Command="{ViewModelMethod SomeMethodName}"/>

Однако это будет медленнее и увеличит связь между представлением и моделью представления. Если представление знает только о свойстве в модели представления типа ICommand, реализация этой команды может полностью измениться (или методы могут быть переименованы) без ведома представления.

person Kent Boogaart    schedule 29.05.2009
comment
Почему это будет медленным? Нужно ли использовать отражение? Но я понимаю упомянутую вами проблему сцепления. - person Jose; 04.06.2009
comment
На самом деле я не думаю, что это будет намного медленнее, поскольку привязка к команде viewmodel также использует отражение. Однако у этого подхода есть недостаток: поскольку это расширение разметки ViewModelCommand не является привязкой, оно не будет обновляться при изменении ViewModel: оно будет оцениваться только один раз (если только оно не подключается к событию DataContextChanged для переоценки, но это уже другая история. ..) - person Thomas Levesque; 06.06.2009
comment
Во-первых, я сказал медленнее, а не медленнее. Важное различие в том. Во-вторых, я говорил о разрешении и вызове вызываемых методов, а не о самой привязке. Использование делегатов, созданных виртуальной машиной, будет быстрее, чем рефлексивное разрешение методов из представления. Так что, помимо всех других недостатков, делать это из поля зрения было бы медленнее. - person Kent Boogaart; 06.06.2009

Полностью не согласен.

Скорость вызова не имеет значения: команды - это взаимодействия с пользователем, они никогда не требуют скорости.

Аргумент о сцеплении тоже ошибочен. Почему {Binding MyProperty} не связывается, а {ViewMethod MyMethod} - есть?

Требование наличия специально созданных «Команд» для обертывания методов - глупо. Команды могут быть полезной реализацией под прикрытием, но у нас уже есть методы на C #, и заменять их чем-то большим и громоздким - неправильно.

А что касается MarkupExtension и Binding, это действительно сложно. Но это может быть сделано. Собственно, это сделано, вы можете взглянуть на проект MethodCall на CodePlex: http://methodcallthing.codeplex.com/

Вы можете использовать привязку, чтобы выбрать «это» для метода, и можете использовать привязку для получения аргументов. И все они живы, т.е. вычисляются во время вызова команды. Еще одна бонусная функция - это выталкивающий результат вызова метода, для этого вы также можете использовать привязку (OneWayToSource).

person Oleg Mihailik    schedule 19.07.2009
comment
+1 за исправление недостатков в ответе Кента Богаарта. Ваше решение интересно, но оно не подтверждает, что ICommands - хороший способ сочетать реализации Execute и CanExecute. - person HappyNomad; 27.11.2011

ICommand дает вам CanExecute, который необходим для включения управления. Простой делегат этого не делает. ICommand - это то, что вам нужно.

person Community    schedule 02.09.2009

Очевидно Microsoft нуждалась в Command, чтобы быть чем-то первоклассным, вероятно, потому, что они считали, что CanExecute необходим для большинства приложений. Я не согласен и думаю, что CanExecute должен был быть просто еще одним DependencyProperty, которое вы бы связали со свойством вашей модели просмотра, но что я знаю?

Возможно, они также думали, что необходимо отделить реализацию команды от контекста данных элемента управления. И снова мне это кажется ненужным, потому что логика должна находиться рядом с данными, с которыми работают, что является фундаментальным принципом объектно-ориентированного программирования.

Лично я избегаю использования команд в MVVM из-за беспорядка, который вы должны создать для их реализации. Я просто позволяю коду представления делегировать события модели представления.

person Mike Gates    schedule 24.06.2010
comment
+1 для хорошей точки зрения, что ICommands в модели представления - это больше кода / сложности, чем небольшой переход между логикой в ​​коде программной части. Даже в этом случае в этом подходе отсутствует логическое сочетание Execute / CanExcute, которое было бы неплохо иметь в модели представления. - person HappyNomad; 27.11.2011

Из-за того, как сформулирован заголовок этого вопроса, читатели могут прийти сюда в поисках альтернативы ICommand, а не просто способа привязать действие пользовательского интерфейса непосредственно к методу viewModel. (Что не имеет большого значения, поскольку оставляет открытым вопрос, что делать с частью CanExecute.)

Использование ICommand проблематично само по себе, потому что оно определено в Windows.Input, а это означает, что для объявления ICommands в ваших ViewModels вы должны ссылаться на WPF и кухонную раковину из логики вашего приложения, и как только вы это сделаете, любой новичок может заметить, что MessageBox и множество других функций графического интерфейса доступны, и могут начать использовать их, что приведет к ужасному беспорядку, состоящему из смешанной логики приложения и логики представления.

Итак, если вы хотите избавиться от using System.Windows, тогда вам нужно избавиться от ICommand, а если вы хотите избавиться от ICommand, то, возможно, вы будете счастливы узнать следующее:

WPF (в частности, конструктор XAML) не требует, чтобы ваши модели представления статически отображали экземпляры интерфейса ICommand.

Под статически здесь я подразумеваю, что дизайнеру не нужно иметь возможность доказывать во время разработки, используя отражение, что ваши командные объекты реализуют интерфейс ICommand; вместо этого WPF проверяет во время выполнения, чтобы убедиться, что действия пользовательского интерфейса привязаны к объектам, которые фактически реализуют ICommand.

Итак, в ваших viewModels (логика приложения) вместо ICommand интерфейса WPF вы можете использовать некоторый Command интерфейс вашего собственного устройства, и все, что вам нужно, это убедиться, что класс, который вы будете создавать во время выполнения, для реализации вашего Command интерфейса также реализует ICommand, чтобы WPF оставался довольным. Таким образом вы можете избежать включения ICommand из ваших ViewModels, и впоследствии вы сможете избежать необходимости ссылаться на System.Windows в логике вашего приложения.

person Mike Nakis    schedule 06.01.2020