WPF MVVM Code Behind
Asked Answered
A

6

18

I try to avoid code behind in views, within my WPF MVVM project.

However I have some things that are very specific to the view. For example when a control gets focus I want the full text to be highlighted (even if a user clicks into the text box).

Here I have a choice to handle this in the view model (which would then need to know about the view, which I want to avoid).

I also have some other code like that does things to the UI when the user presses up down left or right on the keyboard (and they only make changes to the view, not the model or viewmodel) and again I'm thinking the best place for these is in the code behind of the view.

So I'm asking if the code only affects the view (e.g. things like cursor movement, selecting all text in a text box etc..., and not the model or view model, is it okay to put it in code behind, rather than elsewhere.

Wondering what is best practise here, or if anyone else has a better suggestion where to put this code.

Acescent answered 2/1, 2014 at 12:39 Comment(1)
I'm not a great software designer, so instead I focus on 3 things: ease of testing; eliminating duplication; naming things well. Which approach gets you those things?Bucher
C
8

If the behavior is UI related only, then you should not put it in the ViewModel. The highlighting example you gave is a good example of such a case. Having said that, I would suggest you avoid repeating your code by (for example) creating a custom control that highlights the text when it has the focus. This way, you can reuse the control in as many views as you can, your views stay free of codebehind, and if you optimize your control, the optimizations happen across the board.

EDIT:

In light of Ravi's answer, Behaviors are also a way to introduce UI related logic while leaving the View free of codebehind. However, if you are finding yourself repeatedly declaring the same controls with the same behaviors, in my opinion it is better to create a control that incorporates the behavior.

That being said, if said UI logic is going to appear only once in one view, you may consider putting it in codebehind. Although it is quite rare to know in advance that you are not going to need that logic elsewhere.

EDIT:

I think @ken2k 's use of strong encouragement refers to not putting it in the ViewModel, which I also advocate. UI logic should be implemented in the View, as he says. Now, there are a few ways of doing that. One of these is coding it directly in your codebehind, which can lead to repetitious code and maintenance issues. Also, if you employ unit testing, it could put you in a difficult spot. The second is coding such logic into behaviors, which is a good way to encapsulate UI code. You can then unit test the behavior to make sure it works OK. However, you can find (as I did, in many projects) that you have started to pepper every TextBox in your XAML's with behavior tags. If that starts to happen, I would (and have) create a 'HighlightedTextBox' control and use that in my XAML. In summary, my suggestion does not contradict ken2k's, but is a pointer in the direction of resolving some issues you may have when placing logic for your View.

Cloakroom answered 2/1, 2014 at 12:58 Comment(5)
what do you think of ken2k's answer where he is saying it is strongly encouraged?Acescent
My response comment was a bit too long, so I re-edited my answer. Please see above.Cloakroom
My preference for simple repetitive UI behaviors like text highlighting on focus is to use Attached Properties :)Ever
@Rachel, Actually most behaviors make use of Attached Properties in their implementationCloakroom
@BolucPapuccuoglu Yes that's true, I was thinking of something else when I wrote that. Leaving the link though since it seems related to the question and the OP may find it useful.Ever
A
24

So I'm asking if the code only affects the view (e.g. things like cursor movement, selecting all text in a text box etc..., and not the model or view model, is it okay to put it in code behind, rather than elsewhere.

Not only it is OK, but it is strongly encouraged. MVVM is not here for you to write thousands of ugly lines of code in ViewModels, it's here to make the code testable and to introduce a separation of concerns.

If it's purely related to the view (your "focus" example is a perfect example), then just write it in the code behind.

Arcograph answered 2/1, 2014 at 13:5 Comment(1)
Hi I accepted Boluc Papuccuoglu answer, I think your's is correct too, but his was more complete.Acescent
C
8

If the behavior is UI related only, then you should not put it in the ViewModel. The highlighting example you gave is a good example of such a case. Having said that, I would suggest you avoid repeating your code by (for example) creating a custom control that highlights the text when it has the focus. This way, you can reuse the control in as many views as you can, your views stay free of codebehind, and if you optimize your control, the optimizations happen across the board.

EDIT:

In light of Ravi's answer, Behaviors are also a way to introduce UI related logic while leaving the View free of codebehind. However, if you are finding yourself repeatedly declaring the same controls with the same behaviors, in my opinion it is better to create a control that incorporates the behavior.

That being said, if said UI logic is going to appear only once in one view, you may consider putting it in codebehind. Although it is quite rare to know in advance that you are not going to need that logic elsewhere.

EDIT:

I think @ken2k 's use of strong encouragement refers to not putting it in the ViewModel, which I also advocate. UI logic should be implemented in the View, as he says. Now, there are a few ways of doing that. One of these is coding it directly in your codebehind, which can lead to repetitious code and maintenance issues. Also, if you employ unit testing, it could put you in a difficult spot. The second is coding such logic into behaviors, which is a good way to encapsulate UI code. You can then unit test the behavior to make sure it works OK. However, you can find (as I did, in many projects) that you have started to pepper every TextBox in your XAML's with behavior tags. If that starts to happen, I would (and have) create a 'HighlightedTextBox' control and use that in my XAML. In summary, my suggestion does not contradict ken2k's, but is a pointer in the direction of resolving some issues you may have when placing logic for your View.

Cloakroom answered 2/1, 2014 at 12:58 Comment(5)
what do you think of ken2k's answer where he is saying it is strongly encouraged?Acescent
My response comment was a bit too long, so I re-edited my answer. Please see above.Cloakroom
My preference for simple repetitive UI behaviors like text highlighting on focus is to use Attached Properties :)Ever
@Rachel, Actually most behaviors make use of Attached Properties in their implementationCloakroom
@BolucPapuccuoglu Yes that's true, I was thinking of something else when I wrote that. Leaving the link though since it seems related to the question and the OP may find it useful.Ever
L
5

Using Custom controls as @Boluc Papuccuoglu suggested, is good option but before using that i want you to take look here Behaviors in WPF introduction

Linc answered 2/1, 2014 at 13:3 Comment(0)
I
4

It is strongly recommended to have all your view stuff logic at one place. Instead of polluting ViewModel you should always keep View stuffs in XAML and code behind.

ViewModel responsibility is to contain only data part which can be unit tested. With UI stuff in ViewModel, you will make it hard to be unit tested.

As per link here at MSDN, definition of code behind:

Code-behind is a term used to describe the code that is joined with markup-defined objects, when a XAML page is markup-compiled.

As you can see, code behind is partial class of your view. One half is declared via x:Class attribute at root element and other half in form of code behind. So, as per me all UI stuff should be at one place and you should not think twice before placing the view stuff in code behind. (that's what it is meant for). MVVM never meant design without any code behind.

Also ViewModel responsibility is to just provide data to your view via data binding. It should never be aware of UI stuff.

Read more about it here - Code behind and XAML in WPF.

Iodism answered 2/1, 2014 at 17:25 Comment(0)
G
0

More than 10 years after this question was asked, there's still a great deal of misunderstanding (and misinformation) out there about the role of code-behind in MVVM that it seems worth adding a fresh perspective to the already very good answers here.

First we should take a step back and understand exactly what code-behind is. Code-behind is simply a compiler construct, unique to ContentControls like UserControl and Window, that makes it convenient to add bespoke logic to app-specific UI elements that don't need to be retemplated. That's really it. There's nothing about code-behind that can't be accomplished by sub-classing ContentControl and using GetTemplateChild and C#-based event subscriptions. There's nothing magical (or sinister) about it.

Therefore code-behind in and of itself is neither categorically good nor bad in MVVM. What matters is the contents and purpose of the code-behind and whether the code-behind is furthering, or thwarting, the purposes of MVVM.

The purpose of MVVM is principally to promote clear separation of concerns between UI and business logic. This is generally best accomplished by

  • Ensuring the view model and data model layers make no use of platform-specific classes, which is usually best done by splitting the application layers into different C# assemblies and using dependency injection where needed; and
  • Limiting the connection points between the view and view model to XAML bindings

Some people, including many of the frequent posters on this site as of late, focus intently on the first technique but dismiss the second. In other words, they will diligently keep UI-specific code out of the view model layer, but will encourage you to write view-layer code that heavily invokes the view model instead. But this just pushes the problem from one layer to the other. The more view-model reliant code exists in the view layer the harder it becomes to maintian and scale both layers, just as surely as view code existing in the view model layer.

Of course the view needs to have some awareness of the view model, but this should be limited to bindings. In other words the bindings, in XAML, ideally are the only connection points where view and view model meet.

So to bring this back to code-behind, it's a perfectly reasonable practice to use code-behind to do things that only affect the UI as long as you're not directly invoking view model code in the process. But it's a poor practice to write code-behind that directly invokes view model code. Your code-behind should rarely if ever need to touch the DataContext or anything else from the view model layer. If you find yourself needing to do that, then it's time to think about things like attached ICommand properties, injected services, behaviors, etc.

Ganda answered 21/4 at 22:9 Comment(0)
E
-2

How much of your code do you want to unit test? If your view can trigger a command when a control gets focus and your view model can programatically fire an event to highlight the text in that control then you have everything you need to unit test that behaviour with mocked objects. And even if you don't want to unit test (or can't because the bean-counters at your company won't give you the time/budget to do so) then placing that functionality in attached behaviours means they can be used elsewhere. I'm not quite the hard-core MVVM purist as some others on this site but I can honestly say that even in the largest enterprise applications I've worked on I've never once seen a case where WPF code-behind was absolutely required.

Essary answered 2/1, 2014 at 13:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.