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 ContentControl
s 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.