3

For example, I have a ListView that contains a ItemClick event and a SelectionChanged event. Should I entirely skip the code-behind file and put the event handler in the ViewModel, or should I keep the handler in the code-behind?

To me it doesn't seem logical to skip the code-behind because it seems that event handlers are directly made for UI elements. For example, the sender parameter and the related EventArgs parameter typically requires knowledge of a particular type of UI element, and so you would have to cast the sender object to a UI element type so that you can work with the data. In fact, in some cases the sender parameter's type is already given:

private void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
    // In this particular case there is no need to cast the sender parameter to the AutoSuggestBox (UI element!) type because it is already given.
}

Is it safe to work with these UI elements or should UI matters be taken care of in the View only. Please save me from myself. Thanks.

mm8
  • 163,881
  • 10
  • 57
  • 88
LeBrown Jones
  • 887
  • 6
  • 17
  • 2
    You're not wrong. A lot of people end up with VMs that are tightly bound to their views, because they avoid using code-behind so much. If it's view-specific, it should remain in the view imo. A lot of times you can avoid this with clever xaml, such as fancy bindings, or converting user inputs into Commands (although this can tend to come at a cost of type-safety). The best approach really depends on your app, and the MVVM framework you are using. – zzxyz Jun 18 '18 at 18:22
  • If you're not already familiar with it, I suggest googling "command pattern mvvm". These approaches don't eliminate code-behind, but tend to get rid of most of it. (And apologies if your specific examples are these exceptions) – zzxyz Jun 18 '18 at 18:28
  • Thanks for the reply. So for a ListView's ItemClick event or SelectionChanged event, should I put the handler directly in the code-behind and then call a method located in the ViewModel, and pass the appropriate item data to that ViewModel method? I'm getting more confused the more I learn lol. – LeBrown Jones Jun 18 '18 at 19:03
  • That's one approach. Another (more common) is the command pattern I mentioned. I'd run through a tutorial on that (there are tons) if I were you. If you're using Prism or some heavyweight MVVM framework, they probably have their own implementations or patterns. Wouldn't be a bad idea to tag your framework or mention it in the question at least, btw. Even MVVMLite might have something. – zzxyz Jun 18 '18 at 19:17
  • 1
    PS--UI frameworks and patterns are hard to learn, and MVVM is definitely no exception. MVVM is one of the better patterns I've worked with, but not because it's simple. It doesn't help that even within a particular MVVM framework, there tends to be very little agreement on best practices. At a practical, detailed level, you won't even find much agreement on what a VM *is* (or should be). My point being don't feel bad if it seems confusing. – zzxyz Jun 18 '18 at 19:31
  • I think these two posts could be useful for better understanding: [MVVM - view logic: view vs viewmodel](https://stackoverflow.com/q/48925516/7713750) and [Is MVVM pattern broken?](https://stackoverflow.com/q/42931775/7713750) – Rekshino Jun 19 '18 at 06:54
  • It depends what you want. If you go for performance and you're fine with more coupling, then use x:Bind. Remember that you can still x:Bind to methods with no parameters to reduce coupling. If you go for classic MVVM, use ICommand. If you still want performance from the latter, call the command in the viewmodel from the code behind handler, as described here: https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/mvvm-performance-tips. If you ask me, I'd choose x:Bind, it's fast and easy to debug. However, it doesn't have design-time support. – Julien Shepherd Jun 19 '18 at 08:29
  • 1
    Dont use any ui in viewmodel. – lindexi Jun 19 '18 at 10:51

1 Answers1

4

Event handlers belong to the view. You don't define an event handler in a view model, especially not one that accepts a control such as an AutoSuggestBox as a parameter. This defeats the purpose of using the MVVM pattern in the first place. A view model shouldn't have any references or any knowledge about any UI control.

To be able to use x:Bind, you can define the actual event handler in the code-behind of the view and then call a method or invoke a command of a view model from this event handler though. This is fine as long as you don't pass any view related stuff to the view model and don't implement any kind of application logic in the view, e.g:

private void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
    var parameter = ...; //extract the parameter from the args
    ViewModel.Command.Execute(parameter);
}

In XAML frameworks where x:Bind is not available (WPF), you typically avoid defining any event-handlers in the code-behind and invoke commands of the view model directly from the XAML. You can read more about this here.

The point here is that adding an event handler to the code-behind class of the view doesn't really break the MVVM pattern, as long as you implement the testable and separated application logic in the view model. The code-behind and the XAML markup belongs to the same class and invoking a command from the code-behind of this class is just as good as invoking it from the XAML, or from a reusable attached behaviour, as far as the MVVM pattern is concerned.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • 1
    Although ideally, if you're not binding to a command don't use it in a viewmodel to call from codebehind - it's extra garbage and cost infront of a direct method call on the viewmodel. – Johnny Westlake Jun 19 '18 at 13:58
  • Sure; if this is the only way you interact with this view model, you may call a public method of it instead of invoking a command. But that's not my main point here. – mm8 Jun 19 '18 at 13:59
  • 1
    @mm8 So you are implying that x:Bind serves no purpose if the event handler is in the code-behind, because in that case I can simply create a normal event that automatically generates the handler in the code-behind for me? Or is it still better to use x:Bind in all cases? Also, what is the overall PREFERRED approach to all of this? – LeBrown Jones Jun 19 '18 at 14:52
  • You can use x:Bind to bind a method of the view model directly. This is a viable approach if you don't share your view model classes across WPF and UWP clients as it gives you compile-time safety. Binding to a command using {Binding} does not. But if you expose commands from your view model, for one reason or another, you don't need any event handlers in the view. – mm8 Jun 19 '18 at 15:01