4

Where "should" view logic resides normally? In the view (including code behind) or in the viewmodel?

By logic I understand anything what is used to modify view (makes it dynamic), changing its elements properties: Visibility, IsEnabled, Content, etc. based on some conditions.

I am struggling between choosing correct statement:

  1. ViewModel is responsible for all view "properties", if view needs some logic - this should be a job of viewmodel.

  2. View is a viewmodel presentation, viewmodel only needs bare minimum to expose model, the logic thus should be a part of the view.

Logic in the view.

An example, to display some text:

<Grid Visibility="{Binding TextAvailable, Converter=...}">
    <TextBlock Text="{Binding Text}" Visibility="{Binding TextOk, Converter=...}" />
</Grid>

By looking at this xaml you know there are 2 properties in viewmodel: TextAvailable and TextOk, used to conditionally display Text.

Same can be achieved using data triggers. The way is irrelevant, the main point is: logic is in the view. One have to go through view thoroughly to understand both: the logic and implementation.

Logic in the viewmodel.

Xaml is easier:

<TextBlock Text="{Binding Text}" Visibility="{Binding ShowText, Converter=...}" />

and the logic is in the viewmodel:

public bool ShowText => TextAvailable && TextOk;

but this will require notification support, often subscribing/unsubscribing to events (using weak events if deterministic unsubscribing is complicated), to be able to tell the view OnPropertyChanged(nameof(ShowText)) if any relevant property is changed. Thus implementation is well spread among many methods/properties.


I personally prefer to have simple viewmodel and rather complicated view (xaml), full of logic. Recently I found a way to make logic looking really cool (no additional elements and easier to see).

I understand what both approaches can be used and question thus is rather opinion based, but I don't want to mix both approaches in crazy proportions in my software. Which way is more clean and would be better accepted by another MVVM programmer? What should I prefer and why?

Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • *question thus is rather opinion based*. Exactly. We really can't tell which approach would objectively be better. In my opinion, if you intend to reuse a certain logic with another view it should be implemented in a view model. Otherwise it should be in the view. – Clemens Feb 22 '18 at 10:55
  • @Clemens, I'd really like to know which (one or two) you prefer and why. Or you use both and there is no preference to have viewmodel *spoiled* with notification or to have bloated view? Answering "why" then would answer my question. – Sinatr Feb 22 '18 at 11:04
  • I didnt want to mark this to close, but really there is a wealth of information on this topic, it depends how MVVM you want to go. However MVVM apposed to MVC is notification based pattern. you can always use code behind for view based granular logic. and xaml implementation for everything between – TheGeneral Feb 22 '18 at 11:13
  • @Sinatr I have a contra question: If you have a UIElementA as DataContext for UIElementB, belongs UIElementA in your opinion to View or to ViewModel? – Rekshino Feb 22 '18 at 11:13
  • 1
    @Rekshino, tricky question. Since it's UI element (it was designed as view) - it's a [view](https://stackoverflow.com/q/5421874/1997232). I see your point, both are just classes (view is typically xaml, but can also contain code). So my question may sounds as "where to keep some code" (like if it really matter you think).. Well it matter from [tag:design] point of view, which I want to improve. Better design means easy to: support, extend, understand, explain, etc. – Sinatr Feb 22 '18 at 11:32
  • I'm far from being an expert on MVVM, but the way I understand it is that the important part is the separation of concerns. The ViewModel should be in charge of all the business logic, but none of the UI logic (meaning show this, hide that, color this background, drag n` drop, stuff like that). However, I have been reading a lot on the subject lately and seems like writing any code in the codebehind is a big NO NO. You should use behaviors and stuff like that instead. – Zohar Peled Feb 22 '18 at 11:51
  • 1
    @ZoharPeled: Not really - the ViewModel should do the UI logic, and delegate the Business Logic to another layer. The View is responsible for anything visible, so it can contain C# as long as that's about rendering and styling. – H H Feb 22 '18 at 12:09
  • Anything that would not be involved in a restyling should preferably go into the ViewModel. – H H Feb 22 '18 at 12:09
  • @HenkHolterman, why? – Sinatr Feb 22 '18 at 12:10
  • 1
    @Sinatr - your comments about (weak) events don't convince me, you will always need something to keep the ViewModel up to date, no matter where you draw the line with the View. – H H Feb 22 '18 at 12:11
  • 2
    The goal of MVVM is to keep the View light and provide an 'abstract, lookless' UI in the ViewModel that can be much more easily tested. – H H Feb 22 '18 at 12:13
  • @HenkHolterman, view is created by designer using Blend. If I put any logic in the view then that would make designer's job harder. Designer may put his logic to make view nicer (e.g. using triggers to run animations). From other side, I am designer + programmer. And I am trying to solve the problem "complex viewmodel" by making it lighter at the cost of more complex view. Shouldn't I? Why? I wouldn't argue with designer, but there is none ;) – Sinatr Feb 22 '18 at 12:59
  • Why would you lighten the ViewModel? It's much easier to maintain and test. A View (esp. from Blend) is a complex beast you don't want to add anything unnecessary to. – H H Feb 22 '18 at 13:03
  • @HenkHolterman, because I have to subscribe/unsubscribe to events, rise notifications for one properties in other properties setters, constantly think "how not to break the view"... If in viewmodel I only set minimum required for the view to function and move logic into view, then it's going to be much easier to support, e.g. when adding something - I'd add it in the view to related element, no need to subscribe to another event, etc. Btw, I am not using unit tests. Are you doing unit tests for notifications specifically? So you don't care about complexity as long as it still works? – Sinatr Feb 22 '18 at 13:10
  • @Sinatr Which events are you referring to? Other than when creating custom controls and behaviours you shouldn't really need to handle events in WPF. In the ViewModel you should be able to accomplish most of what you need through a combination of property binding and commands. – Steven Rands Feb 22 '18 at 13:56
  • @StevenRands, model and other viewmodels events. If model implement `INotifyPropertyChanged`, then I could just expose instance and view will bind to it directly. But often models have their own events or even polling has to be used to rise notification in viewmodel, when model property has changed. If there are several such properties used in equation, then you need to monitor for each to rise resulting property (used by the view) notification. – Sinatr Feb 22 '18 at 14:08
  • @Sinatr OK, I understand. But surely you would have to do that regardless of how you split UI logic between the View and the ViewModel. To get the View to respond to changes you pretty much have to implement `INotifyPropertyChanged`, either on the ViewModel or a Model exposed by it, like you say. I don't see how you can get around that, or how it affects the way you approach the View. Am I missing something? – Steven Rands Feb 22 '18 at 14:17
  • @Sinatr Also, do you use an implementation of the [mediator pattern](https://en.wikipedia.org/wiki/Mediator_pattern) at all? I would tend to use something like that for VM-to-VM notifications, as opposed to using events. – Steven Rands Feb 22 '18 at 14:20
  • @StevenRands, yes, one example is another viewmodels. Consider e.g. 2 direct bindings to `VM1.A` and `VM2.B` ( `VM` are instances, `A` and `B` are public properties) versus making in current viewmodel property `public bool AandB => VM1.A && VM2.B;`. To notify about `AandB` current viewmodel needs to subscribe to `VM1` and `VM2` property changed event. – Sinatr Feb 22 '18 at 14:20
  • @Sinatr Sorry, I don't fully understand your example and I think we're veering off topic a little. Comments aren't really the place for this anyway. Maybe you could work your example into your original question, or ask another question related specifically to this problem? I think you're asking how best to handle property change notifications for child VMs, but that wasn't what your original question was about. – Steven Rands Feb 22 '18 at 14:28
  • @StevenRands, [sure](https://stackoverflow.com/q/48930678/1997232), let's see if that can be fixed. – Sinatr Feb 22 '18 at 15:05

2 Answers2

3

I think the answer is to do whatever you feel comfortable with. I don't believe that one approach is objectively better than the other.

I guess in a pure MVVM scenario the ViewModel would have no knowledge of its View and no knowledge of how its data is going to be displayed. In practice I think this scenario is very rarely encountered. Most times when writing the ViewModel code you will have a fairly good idea of how its data is going to be displayed and interacted with: in other words, you will know what the View is going to look like, and how it is going to behave.

Given this, I don't think it's a problem to put some UI logic in the ViewModel. I don't mean in the sense of directly manipulating UI elements in the View; rather, having properties on the ViewModel that the View will bind to, such as the Boolean property in your example. The more complicated the logic is, the more likely I would be to place it in the ViewModel, as although you can do logic in the View via visibility converters and data triggers the XAML can get very long-winded. This is not to say that I never use those XAML features, just that I would typically use them for simpler logic.

At the end of the day, the ViewModel is there to support the View: essentially to provide it with properties that the UI elements of the View can bind to, thus providing the conduits through which the two can communicate. Your choice, based on the purity of the MVVM you want to implement, is how much you want to let the ViewModel support the View, and how much you want the View to be isolated.

Steven Rands
  • 5,160
  • 3
  • 27
  • 56
3

In my opinion

2.View is a viewmodel presentation, viewmodel only needs bare minimum to expose model, the logic thus should be a part of the view.

sounds more correct.

What belongs to "bare minimum" depends on business logic requirements(e.g. warning must be shown, because of law requirements, such property would belong to VM) and on flair of designer. So business logic does not belong to the view!

The question "If you have an UIElementA as DataContext for UIElementB, does UIElementA belong to View or ViewModel?" shows, that from point of view UIElementA UIElementB can be considered as VM but UIElementB is really not a VM.
So some classes(also not dependent on presentation framework) which serve as DataContext could and should be put to the view layer(the OP forced me to rethink allocation of some classes).

To summarize:
The less UI-dependent logic in ViewModel the better, but within reasonable limits.

Rekshino
  • 6,954
  • 2
  • 19
  • 44