Review and thoughts on removing .xaml.cs for a view-model first approach

Topics: Conventions, Getting Started, UI Architecture
May 20, 2013 at 7:43 AM
I am learning caliburn and wrote a small piece on how to use caliburn with unity for a true a view-model approach, please help review and correct me.

http://rohiton.net/2013/05/18/doing-view-model-first-approach-with-caliburn-micro-and-unity-the-right-way/
May 20, 2013 at 8:28 AM
Honestly, I don't think that leaving the *.xaml.cs file means that the approach is not 'purely' view-model first. The InitializeComponents call does not distrupt intrinseccally a view-model first approach: it's declaring views directly, without letting CM generate them, that counts as a view-first approach.
A call to InitializeComponents is often required to have a properly initialized view, and using a view that is not fully initialized can lead to potential issues.
In this StackOverflow answer, you can find a nice workaround to have a properly generated view, without the *.xaml.cs file (do not refer to the accepted answer, but to the most voted one); basically, you can inject initialization in a x:Code block:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                    mc:Ignorable="d"
                    x:Class="MyNamespace.MyUserControl">
        <x:Code><![CDATA[ public MyUserControl() { InitializeComponent(); }]]></x:Code>
</UserControl>
Even in a view-model first approach, you cannot simply discard or ignore view initialization; imagine that you are using OpenGL to draw your views: can you assume that no initialization is required on the view-side to have everything up and working?
MVVM is about separation of roles, and is used to leverage the interaction between view and view-model; developing view-model first, means that the view structure is dependant upon the view-model structure, but does not imply that the view should be code-less. The misunderstanding, in my opinion, comes from the bad programming styles acquired duing the WinForm era: too much logic embedded in the controls code. As an answer to this bad practice, many developers decided to put a caveat on their articles/blogs, stating that 'code in views is bad', while the real issue is that code unrelated to the view should not be placed inside the view! There are cases where a bit of code-behind saves a lot of troubles: consider drag & drop inside a control (e.g. re-order items in a list), do you really think that the code used to manage it should/could be placed in the view-model code, in a view-model first approach? A developer using MVVM (again, this is my opinion) can and should use code-behind when needed, avoiding to put logic where it does not belong to.

As a side note: while a lot of people focus on the view/view-model separation part (to the point that code-behind is demonized), few people talks about view-model/model separation. Having code used to connect to a database inside a view-model is far worse than having a *.xaml.cs in your views, from a re-usability, testability and maintainability point of view. :)
May 20, 2013 at 10:34 AM
Edited May 20, 2013 at 10:35 AM
Edit: I completely agree with BladeWise.

Nowhere does it say that MVVM requires the view to be any shape. You should view the *.xaml.cs as an extension of the view and as such it is completely fine to use for view related work. There is a great mix up in what MVVM means, ultimately all it requires is that the Model, the View and the ViewModel are separate concerns, any other rule after that is completely outside the scope of the pattern.
May 24, 2013 at 4:34 PM
Edited May 25, 2013 at 2:02 AM
Hi Guys,

BladeWise: Please note if we remove the .xaml.cs/InitializeComponent then the CM framework calls InitializeComponent for us (see ViewLocator class's GetOrCreateViewType functor), your view is initialized as before, and we do not need CDATA section or any other hacks, .

McDonnellDean: My idea was to remove .xaml.cs was so that the project structure could speak for itself i.e. if we are using view-model first or view first approach.

(1) If you have an InitializeComponent/.xaml.cs then it means you (not CM) is instantiating the view and expect a Bind tag on the xaml file, thus the view would cause VM to be created, as it is view first, CM is not initalizing the view

(2) if you do not have .xaml.cs then it means someone is creating the view model first which causes the view to be created and initialized (created and initialized by CM). As it is view-model first CM is creating and initializing the view

This makes it explicit, maybe CM does not dictate such pattern, but by looking at the examples I thought this was the intent.
I completely understand View first or view-model first is not the goal of MVVM, but with CM we can follow the above and make this convention speak for itself

PS - at my work place we practice Onion/Hexagonal architecture (DDD/TDD), connecting to database inside is a view-model is totally out of picture. :)
May 24, 2013 at 11:21 PM
Edited May 24, 2013 at 11:22 PM
Yes, I forgot CM explicit initialization. Few days ago, I bumped on this issue (not initialized view), that's why I pointed that out. Probably was caused by my ViewLocator customization (forgot to initialize the view).
I see your point about an explicit project structure to identify a view-model first approach, but such a thing is misleading, in my opinion, and forces you to ignore the benefits of code-behind. I feel that removing the xaml.cs is like mutilating the view, denying the fact that all components have the same relevance in MVVM, just different roles.
May 25, 2013 at 1:49 AM
BladWise: I am sorry i didn't understand what you mean by "benefits of code-behind", for cases when you do need to reference view in your view-model, you could make use of attached behavior or make the view-model implement IViewAware. I do not see any reason why you would want to use code-behind .xaml.cs when the same could be done in a neater approach (with attached behavior/IViewAware).

The fact that .xaml.cs is a partial class make it already disfigured, removing .xaml.cs gives you a cleaner structure.
May 25, 2013 at 2:05 PM
Edited May 25, 2013 at 2:08 PM
This is probably more a theoretical discussion, than a proper technical one. :)
From my point of view, a View is not required to be pure XAML, it could even be defined completely in a .cs file (e.g. a custom control), whose XAML is provided by a theme (yes, this is probably madness, and no sane developer would do this, but it is feasible). CM does not work on XAML directly, it just uses a naming convention and a way to locate views or view-models, depending on your choices. So, having or not a .xaml.cs is irrelevant, since you could still provide XAML-only views in a view-first scenario (provided that they are properly initialized, either in XAML or by the CM framework). Code-behind is a feature of the view layer, and it's up to you to decide to use it or not, but the presence/absence of such files is not mandatory in view-first/view-model-first. The fact that code-behind is declared in a partial class, again, is just how the UI framework works, and it is a clean way to detach custom methods and auto-generated ones, that's why I tend to not considered such a thing a disfiguration of the class itself.
Regarding a possible scenario: in my experience, I had to deal with a set of controls that were not really MVVM-firendly. In such a case, I decided to override some methods and provide an MVVM-ish layer to simplify interaction with CM. Such modifications could hardly be baked in a convention or an attached behavior, since such controls had to be heavily hacked from the inside. I suppose that this quite an extreme scenario (you need to use a control that was not designed with MVVM in mind), but the only option in this case is using code-behind... or create a customized derived control and put it in a view (which is essentially the same, provided that such control is used just in that context).

Now, I am not suggesting that code-behind should be used (or abused), I just think that whether a project uses view-first or view-model-first cannot be determined univocally by the presence or absence of the .xaml.cs file: in a view-model-first, not having a .xaml.cs file is neither a necessary condition (you can have *.xaml.cs with no side effects), nor a sufficient one (you can avoid xaml.cs even in view-first); in view-first, again, having a .xaml.cs file is neither a necessary condition (the InitializeComponent is public, so the framework could initialize views anyway), nor a sufficient one (even in view-model-first, *xaml.cs can be present).
In the end, there is nothing wrong in your idea of differentiating view-first and view-model-first depending on the presence of code-behind, but that is just a convention (and a good one, since it forces newbie developers to use attached behaviors and reusable patterns instead of plumbing code in the code-behind) which comes with a probably negligible cost (i.e. cannot use code-behind in view-model-first), but should not be considered (at least in my opinion) as a core part of an MVVM design.

Sorry for the long and preposterous post, it's just that it is a rainy day and I was getting bored! :)
May 26, 2013 at 1:59 PM
Hi BladeWise,

No way I am suggesting that the above methodology of removing .xaml.cs for view-model first approach should mandated by CM or any other MVVM framework (MVVM pattern should be agnostic to it like how you explained), it is just a best practice to make the intent explicit and to tidy up the project structure. :)
May 27, 2013 at 9:12 AM
The problem I have is that you are removing a fundamental feature of the view, that is the ability to have a type safe module that can be coded in C# / VB. Xaml is a declarative language and as such does not have the same power as a code behind. What it lacks in power it makes up in expressiveness, both together enable you to create complex Views. I think you may be misunderstanding the role of the ViewModel and / or the View. When you say View it should mean xaml + cs file. When I hear people talk about doing the above it usually means that they are pushing View related concerns back to the ViewModel, you have to be careful about this.

If you get rid of your code behinds you will end up regretting it later. I appreciate that you are trying to tidy things up and I can also see the problem with having a code behind is the temptation to use it for things that should be on the ViewModel. As an example, this will completely bite you in the ass when you get to building fluid portions of your UI that rely on timers. This sort of stuff does not belong in the ViewModel but cannot be used in the Xaml file either.
May 28, 2013 at 4:35 PM
I do not have much experience in this area, but personally I think if i were to use anything like timers etc. on the view as you have mentioned, I would probably use Rx and use it on the view-model and not on the code behind, I can't think of a decent example that forces me to update UI from the .xaml.cs code behind. If push comes to shove, I would probably use IViewAware or AttachedBehavior that would let my VM have direct reference to the view so it could manipulate it.

If you think this timer base logic should not sit in view-model, may be I would refactor it out that I can then invoke via trigger or EA (worst an extension method or something). Could you please give me an example for your case?, please feel free to correct me, it would help me go long way.

Thanks,
Rohit
May 29, 2013 at 8:41 AM
Lets take a simple example.

A list of address. For this we have an AddressListView and an AddressListViewModel. Because of space issues we cannot show all of address details at once. Instead we are going to swap out the data-template or perhaps trigger the vsm based on a timer so it looks like each address is cycling through the details. The easiest and most painless way to do this is in the code behind. If it becomes common functionality we can extract it out but for now we already have a code behind to help in this scenario so why not take advantage of it. You should only write as much code as you need, nothing more, nothing less.

In terms of timers in the ViewModel, I would be taking these out if their sole purpose is to drive something on the View. The ViewModel should be reactionary. By this I mean it will update it's "state" based on input from the View or the Model. If you think about the example above, it is not really a concern of the ViewModel since it only knows it is a list of addresses, it doesn't know what "size" it should be and therefore it doesn't know it needs to cycle values.

Of course you have to thread a fine line here. The purpose of the ViewModel is to power the View, you don't want to make it too generic, to the point were it doesn't do it's job very well. It's a balancing act. In general if any change to the ViewModel locks it into a specific visual look then that functionality probably belongs in the codebehind and not the ViewModel.