Why to avoid the codebehind in WPF MVVM pattern?
Asked Answered
S

5

64

At the article, WPF Apps With The Model-View-ViewModel Design Pattern, the author who is Josh Smith said:

(1) In a well-designed MVVM architecture, the codebehind for most Views should be empty, or, at most, only contain code that manipulates the controls and resources contained within that view. (2) Sometimes it is also necessary to write code in a View's codebehind that interacts with a ViewModel object, such as hooking an event or calling a method that would otherwise be very difficult to invoke from the ViewModel itself.

My question is ,at the (1), why the empty codebehind is regarded as a a well-designed MVVM.(It sounds that the empty codebehind is always good.)

EDIT: My question is, as the following, why the approach like the AttachedCommandBehavior or the InvokeCommandAction is tried to avoid the codebehind coding.

Let me explain more detail.

As far as the (1) is concerned, I would think like the following situation as from the AttachedCommandBehavior. As the Border doesn't implement the ICommandSource for the MouseRightButtonDown, you cannot commonly bind the event and the ICommand, but can do with the AttachedCommandBehavior.

<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
    <local:CommandBehaviorCollection.Behaviors>
           <local:BehaviorBinding Event="MouseRightButtonDown" 
                  Command="{Binding SomeCommand}" 
                  CommandParameter="A Command on MouseRightButtonDown"/>
    </local:CommandBehaviorCollection.Behaviors>
</Border>

OR

We can do this with the System.Windows.Interactivity.InvokeCommandAction.

<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseRightButtonDown">
            <i:InvokeCommandAction Command="{Binding SomeCommand}" 
               CommandParameter="A Command on MouseRightButtonDown"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Border>

BUT,

We use the following XAML and its codebehind having the Border_MouseRightButtonDown method, which is linked to the (2) Josh Simth said above.

<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>

I think using the codebehind as above is not bad just because the difference between these is only where binding a command or add event handler is.

What do you think about this?

Stgermain answered 21/6, 2011 at 6:43 Comment(1)
I think, if Border_MouseRightButtonDown does not trigger any actions on the view model, and does not modify it's state, it's totally OK. Placing a lot of UI code in the ViewModel will eventually end up with code behind transferred to ViewModel.Beverie
A
91

why the empty codebehind is regarded as a a well-designed MVVM

Having a code-behind file which consists solely of a call to InitializeComponent() in its constructor means you have achieved purity - you have absolutely zero logic in your codebehind. You have not polluted your view with any code that rightfully belongs in the viewmodel or model. This means a couple of things:

  • the viewmodel (and model) is easier to test in isolation
  • you have achieved a good level of loose coupling, which has excellent benefits from a maintenance and extensibility perspective

The benefits really become noticeable when you have to change your UI, i.e. you switch from using a ListView to a DataGrid, or you change from using the standard Microsoft controls to using some other vendor's.

As mentioned though, it is sometimes impossible to avoid a little code in the code-behind file. What you should ensure is that the code you do have is purely UI related. As an example, if you have ComboA and ComboB, and ComboB is set in response to the selection in ComboA, then setting the SelectedIndex of ComboB from the view is fine, but setting the Items or the SelectedItem of ComboB is not - those properties are both data related and should be specified via binding to the viewmodel. The SelectedIndex property is directly visual related and somewhat independent of the actual data (and it is irrelevant to the viewmodel).

If you do access the viewmodel from code-behind in the view, you should try and do it via an interface. This means your viewmodel is injected or given to the view as an interface. (Note that the binding subsystem doesn't know or care about the interface, it will continue to bind in its normal way. What this achieves is better code, with less tight coupling). The way I code it, the viewmodel has no idea that a view exists, and the view only knows about the viewmodel as an interface.

One thing to remember though is that MVVM is a pattern, and a pattern is simply a recipe or prescription for achieving a certain result in a certain situation. It shouldn't be treated as a religion, where non-believers or non-conformers are going to go to some purgatory (although adherence to the pattern is good if you want to avoid the purgatory of maintenance hell and code smell).

If you want an excellent example of how this particular pattern helps, try writing a few reasonably complicated screens in ASP.Net, and then write the same in WPF or Silverlight, and note the difference.


Edit:

let me answer some of your questions, I hope it helps....

the viewmodel's (model of view) role , in my view, has UI logic and state of a view

The viewmodel should never have any UI logic or "view state" in it. For the purposes of this explanation, I would define view state as scroll position, selected row index, selected index, window size, etc. None of those belong in the viewmodel; things like SelectedIndex are specific to the way the data is shown in the UI (if you change the sort order of a DataGrid then the SelectedIndex can change, even though the SelectedItem is still the same). In this particular case, the SelectedItem can be bound to the viewmodel, but the SelectedIndex shouldn't.
If you need to keep track of UI session type info them then you should come up with something generic (for example, I have persisted view state before by saving important stuff into a KeyValuePair list) which is then "saved" with a call to the viewmodel (via the interface I mentioned previously). The view has no idea how the data is being saved, and the viewmodel has no idea the data is coming from a view (it has simply exposed a call through its interface).

and the view's role is displaying some contents and synchronizing the viewmodel(having databinding code)

Yes, the view's responsibility is simply to visually display data presented by the viewmodel. The viewmodel gets the data from the model (the model is responsible for making database calls or WCF webservice calls, this will usually be done via a "service", but that is a whole other discussion). The viewmodel can then shape or manipulate the data, i.e. it may get a list of all customers, but only expose a filtered version of that list (maybe the current customers) in a public property which the view can then bind to.
If the data is to be manipulated into something visual (a common example is an enum value being translated into a color), then the viewmodel still only has the enum value(s), and the view still binds to that value, but the view also uses a converter to translate the pure data to a visual representation. By using the converter the viewmodel has still avoided doing anything UI related, and the view has avoided any real logic.

Agronomy answered 21/6, 2011 at 7:9 Comment(9)
Your answer is great stuff for me. Could you let me assure this question? Sorry for annoying. Though I don't understand deeply, the viewmodel's (model of view) role , in my view, has UI logic and state of a view, and the view's role is displaying some contents and synchronizing the viewmodel(having databinding code). It would be more reasonable that the UI logic is in the viewmodel than the UI logic is in the view. In spite of it, if it would be difficult or impossible and the UI logic is only related with the view, the UI logic would be in the view. This is right?Stgermain
@jwJung, i've expanded my answer, see if it helps.Agronomy
I think you point very sharply the answer of this question. I'm completely understood through your efforts. Thanks a lot.Stgermain
Ok, so I agree, the UI logic should DEFINITELY not be in the ViewModel, but you say that the View should never have any code in it either, so where the heck does the UI Logic (ie View State) code go, everyone is so damn stuck on having no UI Logic code behind in the View, and I just dont get it. According to this here: en.wikipedia.org/wiki/Model_View_ViewModel . The MVVM model does NOT stipulate that there can be no view code behind. So why this fixation?Melisent
I say that as long as the code in your View Code Behind is ONLY related to the state of the THAT view then put as much code as you want in there, just make sure that ANYTHING that can be done by the ViewModel is executed on the view model from the View instead of in the view itself. Also make sure that the ViewModel is totally abstracted from the View, in other words there should be nothing relating to the view (ie. List index is not correct), however, a Model property index is OK, so it depends on the terminology used.Melisent
@Aaron - don't get me wrong. Only the fundamentalists dictate that there should be zero code in the code behind of the view (notice I call them fundamentalists, not purists). I am all for view/UI related code in the code behind because too often I have seen that code shoe horned into the VM because people thought they had to. Sometimes it will be a tough decision about where the code should go, and sometimes the code will be split between the code behind and the VM.Agronomy
@Slugster: Im glad there are other people out there who are like me, I was beginning to think I was the only one! Cheers :)Melisent
If I put a button on the view that changes the background of the view via code behind why on earth should this be avoided? Imo it is more readable than XAML. What about when the view model retrieves data and then needs to set the focus of a tab the view? This must have a call from the vm to the view. Most mvvm I see is technically closer to mvp imo.Disappearance
@rolls Are these rhetorical questions? The VM should not be setting the focus of a tab in the View - instead the view should detect when the data load has finished (i.e. by using events), then the view should do the focus change. Remember that the VM has no idea how the data is being rendered in the view.Agronomy
R
11

The MVVM can split code and page design completely; coders just care about coding and designers only care about design. But:

  1. I've never seen any designer who using Blend or understanding XAML.
  2. Almost all XAMLs are written by coder himself.
Refutation answered 21/11, 2014 at 2:40 Comment(0)
A
5

There is nothing inherently bad in code-behind. For simple cases, it's fine to have it. However, UI logic can get difficult to manage in many scenarios. Encapsulating that logic in attached behaviors and view models allows us to isolate the variables (and test them) so that it's easier to comprehend and maintain.

If testability is a concern, the more of your UI logic that you can encapsulate in viewmodels and attached behaviors, the more you you will be able to verify without resorting to UI testing. (While it doesn't eliminate the need for UI Testing altogether, it does provide a first level of verification before engaging in UI Testing which will be more time/resource intensive.

Acarid answered 21/6, 2011 at 7:7 Comment(0)
S
2

I think the quoted section refers to the way data is visualized. I think they mean you should not write code in code behind that is, for example, related to how or where the data is displayed (for example something like: label1.Text = ...). Doing things like that using bindings makes it easier to separate design and code (what happens if you need the data to be displayed in a text box named "tbTest" in a later version? You'd have to change your code behind).

They are not saying that you shouldn't have any code in code behind - they are just saying that in an ideal world, you'd only react to events or process data that could not otherwise be processed.

At least that's what I understand from the section you quoted.

Sulphide answered 21/6, 2011 at 6:56 Comment(1)
I also think your answer that the viewstate should place in the viewmodel is good point. However, why the approach like the AttachedCommandBehavior or the InvokeCommandAction has been tried is the my point.Stgermain
T
-1

The MVVM pattern is powerful but I find it too 'Purist'. I can see benefit is having the code behind handle all the commands and properties in the view while the ViewModel is concerned with any translation to business model properties. A benefit of this is that if you wish to change the user UI, perhaps from desktop to browser it is likely to be just replacing the View and its code behind.

Just my thoughts!!

Tergal answered 16/7, 2019 at 16:38 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.