Repost MVVM Infrastructure: DelegateCommand

The original post is available here: MVVM Infrastructure: DelegateCommand; it is one of the quartet  of Kent Boogaart's MVVM pattern's infrastructure. 

 

the reason to respost the thread is because there is long debate over whether or not the RoutedCommand is too heavy due to its complexity in MVVM patterns, where most of the work is done on the ViewModel, and the RouteCommand, due to its complication involving connecting the View and ViewModel through the use of CommandBindings.

 

 

Most of the time we only rquires something that is as simple as a delegate call.

 

RoutedCommand has some benefit over the DelegateCommand, among the few, they are.

 

  1. It is the only concrete impl of WPF, and UI element in WPF are inherited from UIElement which has a CommandBinding Collection by default.
  2. WPF has special treating to RoutedCommand, e.g if the ICommand is not a RoutedCommand, the command Target is ignored. (See the Command Target section in WPF Routed Commands: Overview and Examples)
  3. routedEvent travels as it names says, the visual tree, while the DelegateCommand use directly a delegate, which is faster, but without the advantage of separate the handler from its source. 

 

 

Prism has provided a good implementaion DelegateCommand, while Kent Boogaart, has implemented his own DelegateCommand Prism will introduce extra dependencies. 

 

MVVM Infrastructure: DelegateCommand

Download Command.cs 
Download DelegateCommand.cs 
Download DelegateCommandExample.zip

This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.

Related posts:

  1. POCOs versus DependencyObjects
  2. ViewModel
  3. DelegateCommand
  4. ActiveAwareCommand

In my last post I discussed my ViewModel base class. In this post I’m going to start showing you some infrastructure around commanding.

WPF's commanding support enables you to hook up UI interactions with code without tightly coupling the two. User actions are abstracted into implementations of WPF’s ICommand interface, which are then associated with controls that implement ICommandSource. Essentially, it's a layer of indirection. The controls in the UI aren't intimately aware of the command logic they are connected with, and the command logic isn't aware of the controls it will be associated with.

When starting out with WPF commanding, you will soon come across the RoutedCommandclass. This particular command is yet another layer of indirection, in that its execution logic involves finding something to execute and calling that! Starting with the focused element, it searches up the visual tree for an element that has a matching CommandBinding in itsCommandBindings collection. If the RoutedCommand finds a matching CommandBinding, it executes that CommandBinding's Executed delegate.

Routed commands work great in certain scenarios, and are prevalent in WPF. Indeed, the only concrete ICommand implementation that comes with WPF is the RoutedCommand (and its subclass, RoutedUICommand). Unfortunately, this has caused WPF commanding to become somewhat synonymous with RoutedCommands, which is not at all accurate.

imageThe thing is, routed commands are not always a great fit for MVVM development. Typically the logic for your command execution belongs in the view model. For example, suppose you have aCustomersViewModel that maintains a list of CustomerViewModels, and you want to expose a command that deletes the selected customer. The logic for that command should reside in the CustomersViewModel, since it knows best what to do when a deletion is requested.

If you were to use a RoutedCommand, you would then need a CommandBinding somewhere in the UI in order to connect a visual element to the DeleteCustomerCommand. In our example, we would likely stick a CommandBinding in the CustomersView and associate it with the deletion command and methods on the view model. Without the CommandBinding, the RoutedCommandwon't find a handler for the command and the Delete button will be forever disabled.

Using routed commands with MVVM ends up being messy, sub-optimal, and requires the view be more tightly coupled to the view model. And in some scenarios, it’s not even possible (I’ll discuss such a scenario in my next post). But the good news is, we don't have to use routed commands. All we need is an appropriate implementation of ICommand – one that is more conducive to MVVM development.

imageIf you think about it, all we really want to do is have a command that – when executed – invokes a method in our view model. And when the command is queried for its executable status, it executes a different method in the view model. To continue our customer example, that command might be associated with a Button in ourCustomersView. The availability of the command would be dependent upon the user first selecting a customer (you can't delete a customer if you don't know which customer to delete). The execution of the command might execute a DeleteCustomer method on the CustomersViewModel.

Sound simple? That's because it is! Far simpler than attempting to use routed commands for this scenario.

The command implementation I use is called DelegateCommand, simply because it invokes delegates when executing and querying executable status. Other people have different names for this type of command, the most common of which seems to be RelayCommand. That's fine - call it what you will.

Prism has a DelegateCommand too, which is almost exactly the same as this one. However, the reason I have my own is simply because we don't use Prism in our project, and it would be a large overhead to pull it in just for the sake of a class or two. Besides, if you're doing a non-composite WPF app, Prism may not be a good fit.

To create a DelegateCommand, you simply give it one or two delegates to use. If you give it only one delegate, the command is assumed to be always available. That is,ICommand.CanExecute() will always return true.

In our CustomersViewModel, we create the DelegateCommand as follows:

1
_deleteCustomerCommand = new DelegateCommand(DeleteCustomer, CanDeleteCustomer);

We then expose the command from a property in our view model:

1
2
3
4
public ICommand DeleteCustomersCommand
{
     get { return _deleteCustomerCommand; }
}

And bind to it in the view:

1
< Button Command = "{Binding DeleteCustomersCommand}" >Delete</ Button >

It’s as simple as that. The delegates supplied to the DelegateCommand will be invoked at the appropriate times and our Delete button will only be enabled when a customer is selected. You can see all this and more in the download.

Incidentally, DelegateCommand inherits from a base Command class. That’s just to keep the code DRY with respect to other command classes I have, such as the ActiveAwareCommand. I’ll talk about that one in the next post.

† The application in question was built before Prism shipped, elsewise we would be.

Download Command.cs 
Download DelegateCommand.cs 
Download DelegateCommandExample.zip

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值