4
votes

I have begun creating a wpf mvvm app. It seems a vital ingredient to the ViewModel is a bunch of ICommands to have a loosely coupled way of allowing the view to interact with the viewmodel.

My question is this, why can't I bind directly to a method?

I have used Josh Smith's RelayCommand implementation of ICommand that allows you to inject delgates into an ICommand object, but really, is there some easier way to allow a button push to call a method in the viewmodel?

I'm new to MVVM, I believe I need some enlightenment

5
You can bind to a method: <Button Click="YouEventHandlerMethod"/>... But you probably want to consolidate enable/disable logic and execution logic together? That's why you need command. - Lex Lavnikov

5 Answers

7
votes

You can't bind directly to a method because Button (for example) doesn't have a property that accepts a delegate. Instead, it has a Command property of type ICommand. A RelayCommand (aka DelegateCommand) is just an ICommand that wraps delegates.

I see no technical reason why it wouldn't be possible for the view to bind to specific methods on the view model by way of a markup extension:

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

However, this would be slower and would increase the coupling between the view and view model. If the view knows only about a property on the view model of type ICommand, the implementation of that command could change completely (or methods could be renamed) without the view being aware.

6
votes

I completely disagree.

The speed of invocation bears no relevance: commands are user interactions, they never require speed.

Argument about coupling is flawed too. How come {Binding MyProperty} is not coupling but {ViewMethod MyMethod} is?

Requirement of having specially crafted 'Commands' to be wrapped around methods is a silly one. Commands might be useful implementation under the cover, but we already have methods in C# and replacing them with something big and bulky is not right.

And that thing about MarkupExtension and Binding, it really is difficult. But it can be done. Actually, it is done, you can have a look at MethodCall project on CodePlex: http://methodcallthing.codeplex.com/

You can use binding to choose 'this' for the method, and can use binding to fetch arguments. And all those are live, i.e. being calculated at the time the command is invoked. Another bonus feature is push-out result of method call, you can use binding for that too (OneWayToSource).

5
votes

ICommand gives you CanExecute, which is needed for control enabling. A simple delegate does not. ICommand is the way to go.

3
votes

Apparently Microsoft needed a Command to be something first-class, probably because they felt having the CanExecute was necessary for most applications. I disagree and think the CanExecute should have just been another DependencyProperty that you would bind to a property of your viewmodel, but hey, what do I know?

Possibly they also thought that there was a need to decouple the implementation of a command from the control's datacontext. Yet again this seems unnecessary to me because the logic should live near the data that is being operated on, as is a fundamental principal of OO.

Personally I avoid using commands in MVVM because of the mess you have to create to implement them. I just let the view's code-behind delegate events up to the viewmodel.

1
votes

Due to the way in which the title of this question is worded, readers might arrive here looking for an alternative to ICommand, instead of just a way to bind a UI action directly to a method of a viewModel. (Which is of little value, since it leaves open the question of what to do with the 'CanExecute` part.)

The use of ICommand is problematic in and of itself because it is defined in Windows.Input, which means that in order to declare ICommands in your ViewModels you have to reference WPF and the kitchen sink from within your application logic, and once you have done that, any noob might notice that MessageBox and a vast array of other GUI functionality is available, and might start making use of it, resulting in a terrible mess of mixed application logic and presentation logic.

So, if you want to get rid of using System.Windows, then you need to get rid of ICommand, and if you want to get rid of ICommand, then you might be happy to know the following:

WPF (specifically, the XAML designer) does not require your viewModels to statically expose instances of the ICommand interface.

By statically here I mean that the designer does not need to be able to prove, during design time, using reflection, that your command objects implement the ICommand interface; instead, WPF checks at runtime to make sure that UI actions are bound to objects which do in fact turn out to implement ICommand.

So, in your viewModels (application logic) instead of the ICommand interface of WPF you can be using some Command interface of your own device, and all you need to ensure is that the class that you will be instantiating at runtime to implement your Command interface also implements ICommand to keep WPF happy. This way you can avoid including ICommand from within your ViewModels, and subsequently you might be able to avoid having to reference System.Windows in your application logic.