1

Generally, I think it's good practice to use ICommands to handle button clicks that need to do something (such as save user input). However, when the button does something strictly on the UI, like open a modal dialog, the view model doesn't need to handle that, or even be aware it happened. In such cases, it seems like it makes more sense to just use the button's Click event handler, but mixing and matching like that seems like a potential anti-pattern. Am I correct in thinking so?

For example:

var openModalButton = new Button();
openModalButton.Click += OnModalButtonClick;

//Elsewhere in the view...
var saveInputButton = new Button { Command = _vm.SaveInput };

It's not inherently clear by looking at the code why one uses a command, and why one uses a click event.

Jedediah
  • 1,916
  • 16
  • 32
  • I'd strongly recommend reading [this answer](http://stackoverflow.com/questions/1619505/wpf-openfiledialog-with-the-mvvm-pattern). It sticks with using an `ICommand` for the View to bind to. But purely UI logic is still defined in the code-behind. What I like about this type of interface solution is it forces various WPF projects to be consistent with how it handles these types of application operations (assuming you have your Windows implement it of course). – Michael Jul 23 '15 at 20:27

3 Answers3

3

Of course consistency is important as Robin pointed out. However there are scenarios when you'd not want the ViewModel to be involved. Then there's no choice and I think it is much better to break consistency here but not to break the pattern (MVVM) by handling stuff in the ViewModel that is not its job.

You took modal dialogs as an example and I do not agree that the ViewModel should not know about it. Of course the ViewModel is not allowed to directly open that dialog, settings its owner and the likes. But the dialog most probably is part of the workflow and it's just fine to know about the current state of the workflow in the ViewModel. So there should be a layer in between. A service or something similar that allows you to say "I want to show the UI for X" and that solves this by using a modal dialog. The ViewModel doesn't know about the modal dialog but it knows the current state, for example that it is asking the user whether to save changes. Of course this requires some kind of infrastructure handling the special cases and tricky parts. MVVM frameworks offer solutions for this.

If that sounds like overkill for your application simply put that event handling in the code behind of the view. It is not beautiful style but it does not break the MVVM pattern.

In one phrase: Better to mix than to violate the pattern.

dotsven
  • 326
  • 2
  • 9
  • While writing the above Robin mentioned dependency injection. That's exactly what enables us to bring together that modal dialog and the ViewModel. You may choose to implement the DI yourself for example by using interaces and services or you can use one of the existing frameworks. Anyways you'll have to choose if it is worth the effort. If the application is very small it may not but if it is a huge one you'll better take some time to find a combination of techniques and frameworks that handle this. – dotsven Jul 23 '15 at 20:49
3

Jedediah,

I usually do as you and mix and match. Usually (for me) there is only 1 or 2 cases like this, and the idea of patterns and architecture is to make the code easier to read and simplify things. Adding a lot of code just to ensure the MVVM pattern is followed seems like it complicates things in this case. That said, the way I've seen this usually handled is bind the button to your ViewModel with ICommand, and then use a "mediator" or "service" to launch the dialog. You could do a Google Search on: "HOw to handle opening a modal dialog the mvvm way " and/or see:

Open dialog in WPF MVVM

The "pretty" way to make a modal dialog in WPF with Prism and MVVM Pattern

Handling Dialogs in WPF with MVVM

Good luck!

Dave

Community
  • 1
  • 1
Dave
  • 8,095
  • 14
  • 56
  • 99
0

I think it is an anti pattern, or not very cool thing at least,first because you're mixing the two approaches and that's not consistent, secondly because I believe that that needs always to be handled in a Command instead of an Event handler, why ?

the view model doesn't need to handle that, or even be aware it happened. In such cases, it seems like it makes more sense to just use the button's Click event handler

Not really, additionally to the fact that Commands help you separate your object from the logic that executes the Command thus it makes it loosely coupled, but it also help enhancing the reusability of your code, for instance someone in the future may want to change that button into a whole new control that might have a different event, and different args for the corresponding event ... and that breaks your code, using a command however is better and is always compatible and reusable.

Moreover, Laurent Bunion explains in this article how Events are problematic :

For all their utility, event handlers have one problematic side effect: they can create a tight coupling between the instance that exposes the event and the instance that subscribes to it. The system needs to keep track of event handlers so that they can be executed when the event is raised, but the strong link this creates might prevent garbage collection. Of course, this isn’t an issue if the event handler is a static method, but it is not always possible to handle all events with static methods only. This is a frequent cause for memory leaks in .NET.

Another consequence of the tight coupling between an event and its handler is that the event handler for a UI element declared in XAML must be found in the attached code-behind file. If it is not there (or if there is no attached code-behind file), the compilation will fail with an error. This is especially an issue when working with list controls and associated DataTemplates. When an element of the template must be actuated, an event handler can be defined, but as a consequence, the DataTemplate cannot be moved into an external ResourceDictionary.

AymenDaoudi
  • 7,811
  • 9
  • 52
  • 84