Put it in codebehind or in the ViewModel - wpf

I would like to get some opinions on when/if it is ok to put code in codebehind. I've only been at this for less than a year now. So, I still consider myself very "green". I come from a Delphi background. So, the learning curve has been tremendous to say the least – learning WPF, XAML, C#, Unity, Prism, MEF, .NET, MVVM, etc… Fun but very challenging.
When I first started less than a year ago, the idea in the office was no code in codebehind if at all possible and no view specific code in the VM.. So, I have racked my brain many times to determine how to push literally everything into the VM and keep what I think is view specific code out of the VM only to come up short almost every time. I’m to the point now, I’m beginning to think codebehind is not always bad or “wrong”. I have recently been trying to clean up some of our views by attempting push any codebehind into the VM which led me to find a neat factory class at http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html. This allows you to bind routed events to ICommands in the VM. It works like a charm and I was able to significantly reduce some of our codebehind with it. However, after doing so, I’m now questioning my decision to do so. My approach followed the philosophy that codebehind was bad/wrong unless absolutely required. Now that I have had a little time to think about it, I’m not so sure the refactor was the best idea.
The following is an example of a view I refactored. We have a new account view where the user enters an SSN and must rekey the SSN before the new account can be created. The view has a label that displays text to tell the user if the SSN and rekey SSN do not match and the OK button is not enabled until they both match. Once the SSN and rekey SSN match, the label disappears (yes I know… I hate that but I’m just the developer) and the OK button is enabled. So, the hiding/showing of the label and enable/disable of the OK button is triggered from the TextChanged events in the SSN and rekey SSN text boxes. Initially I had logic in codebehind to compare the two textbox values and set viewmodel properties appropriately to update the visible property of the label and the OK button’s enabled property (yes their properties are bound in XAML). After finding this new factory class, I used it to push all of the code into the viewmodel and the view works just like it did before just without codebehind. After successfully refactoring the view, I am now second guessing the decision to refactor.
My concern is, what if we want to have a different view in the future and the new view doesn’t want to handle mismatched SSN’s in that fashion. Maybe the new view would allow the user to type in mismatching SSNs and then display an error message when the OK button is clicked. Should the new view have to accept the extra overhead of code in the viewmodel executing for every keypress in the text boxes? That just doesn’t sound right to me. I’m starting to think the viewmodel should contain what is required to support what the view needs but not do everything for the view. The view should be able to make decisions based on something in the viewmodel but not depend on the VM to hold its hand – right?

The XAML and matching .cs file make up the view. Because of that there's nothing wrong with putting code in the codebehind as long as it's for the view itself.
There is certainly nothing "wrong" with codebehind.
Here's how I'd handle your SSN example:
Bind both SSN fields to properties on the view model
Bind the OK button to a command in the view model (I'm a big fan of the Delegate Command concept)
The command should implement the CanExecute portion and only return true when both SSNs match.
It doesn't seem that the SSN matching is a view concern, it's a business practice. It belongs in the view model. What would be in the view is how your application shows that the SSNs do or don't match.

Related

How much view-agnostic is a ViewModel supposed to be in MVVM?

Let's imagine a very simple UI, where there's a list of checkboxes. When you click on any of them:
1) if it's not selected, it should create a workspace with this checkbox name (and more logic then is available in that workspace, but that's irrelevant to the question). The checkbox naturally then becomes selected;
2) If it's already selected, it should turn unselected and should destroy the associated workspace.
The straightaway form of implementing this is to have the View look at the state of the clicked checkbox and depending on being already selected or not do a viewModel.createWorkpace() or viewModel.destroyWorkspace(). But then that means that this logic is in the View -- I get the impression it'd be better to have it in the ViewModel.
I've read that the ViewModel for diverse reasons should not know the View. But one thing is not having a physical dependency to the View (an object reference, for instance) and another completely different is not even being aware that the View may have checkboxes, as in this example.
It gives me the impression that actually there's really not big of a point in making the View and ViewModel that much different, and in fact, the closer the ViewModel is to the View, the easier it is to bind data between the View and ViewModel.
How should I deal with this situation and why?
Thanks
The idea is to decouple the view and viewmodel.
You should be able to instantiate the viewmodel separately.
The primary reason for this is not some vague neatness or something.
The primary reason is so you can easily exercise tests on your code by instantiating a discrete class.
The view should do view things which are related to displaying data and allowing the user to interact.
The viewmodel should have the code that acts on those interactions and presents data to the view.
This does not mean the view should have no code at all.
If there is code, however, it should be view specific.
It's a good idea to use re-usable code such as behaviours.
Because then you can manually test these and prove they work. Then re-use your proven code.
Similarly with converters, validators etc.
All code.
All used in views.
I suppose it is theoretically possible to write an app which has no converters or validators or behaviours. I've never seen a serious business app didn't have all three though.
It is less important that the view knows nothing about the viewmodel than the reverse.
You're not going to instantiate the view to exercise tests unless you also have a viewmodel instantiated for it.
That doesn't mean you should just bung all your code into code behind though.
Why is that exactly?
Because the god of MVVM will strike you down with his lightning bolts?
Nope.
Because this will make future development easier?
Well it might, but not usually so much you'd notice.
Why then?
Because instantiating a view with it's controls is very slow.
They unavoidably have a lot of dependencies you can't mock.
It is likely to depend on resource in the application, so you'd have to instantiate an application and merge resource dictionaries.
Views often depend on swathes of libraries, pictures, usercontrols etc etc.
None of which you can mock.
So you need everything.
By the time you automate instantiating everything in some test runner and iron out clicking on buttons etc...
Your head will be hurting and you'll find those 2000 test you're theoretically wanting to run in a couple of seconds every 10 minutes take much longer than that couple of seconds.
You can't do "proper" TDD if you instantiate views in tests.
To answer your workspace checkbox question.
It depends on what a workspace is really.
A common pattern would be to initiate code in the setter of a viewmodel property bound to the ischecked property of each checkbox.
That might be in a viewmodel presented per checkbox which had the name of the workspace, it's type or whatever is required to do it's check-uncheck stuff.
Each would hold some sort of reference to these things it's creating so it can dispose them or whatever when that ischecked value becomes false.

MVVM without 'standard model'

Almost every tutorial explains MVVM in WPF in the same manner: We have some entity (Person, Student, Car etc) - we create a Model class for it that will only carry data (it might also implement INotifyPropertyChange, IDataErrorInfo and whatnot - doesn't matter now), then we create a View-Model for that class, that will query and/or save our entity/ies somewhere (most likely via Commands) - our View will bind to the View-Model and voilà.
Let's say we have an application that won't, for a difference, work with querying/saving entities. Let's say it should contain a button that when clicked will download an .exe file (in a background thread) and will launch it. I'm curious, how would you approach this (architecture-wise) - would you actually create a folder/class named 'Model' for that program? What would it contain? How I see it, I'd have two abstractions - one for downloading a file and one for launching it. I'd inject them to View-Model and call their methods (via Command) and that's it. Or should it be a Model class that contains these abstractions? I know this question might seem strange, but it's something that's been bothering me for some time.
Btw, I realise the title of this post doesn't tell much - I didn't have a better idea for it, if someone does - feel free to change it.
For the example you provide, how the MVVM model will be setup is as follows. Let us assume that you want to download some data and show it in a DataGrid which is part of your view. In the View you add your DataGrid and Button, bind your button click to the ViewModel via a command. Bind your DataGrid via ItemSource to some ObservableCollection<T> in the view model (the view model must implement INotifyPropertyChange). Now, when the user clicks the button the command will fire and you can go and fill you ObservableCollection<T> with data via the download, the downloaded data which is bound to the UI will automatically display...
I hope this helps.

Custom property dependant on other properties

Advance apologies for the event-style explanation; there's a lot of factors that I feel all play a role of their own. WPF is not my native framework of choice, and it probably shows. :)
Old situation: I had a window with several controls. Depending on their selections, I used multibindings and a converter to determine whether certain controls needed to be shown that inform the user about the implications of their changes before they'd eventually confirm them by OK (or simply dismissed by using Cancel). This worked perfectly.
Problem: Too many controls as time went by, too much clutter.
Solution: Put stuff in different Pages so it becomes easier to browse for the user. In order to have changes-to-be persist as a user arbitrarily browses between the pages, I create these dynamically and put them in a cache (Dictionary<string, BasePage>, see below), from which they will be pulled as the user chooses them.
Consequence: I need to decouple the bindings to the notification controls as the different options are now on different pages.
Solution? I put a BasePage class in that exposes certain abstract read-only properties that define the various aspects that the window needs to know about in order to do its notifications. For example, a bool requiresReboot property defines whether the current state of things on that page requires a reboot to take (full) effect. A specific page implements the property based on its controls.
Problem: I do not know how to keep create a proper binding that properly gets updated as the pages are changed. I tried giving my notification controls a binding to the Dictionary<string, BasePage> with a converter that checks all pages and the relevant property.
Questions:
1) How do I create a proper property for this purpose? I presume I need a DependancyProperty as I did a fair bit of reading on MSDN, but I can't figure out how this fits together.
2) How do I make a link between my custom property so that it allows (multiple) control(s) on a page to change that property? Do I use INotifyPropertyChanged somehow? My old example bound against several CheckBox.IsChecked properties in XAML. I am trying to avoid putting tons of events (OnChange, etc) on the controls as the original code did not need it and I have been told it makes for a messy solution for as far WPF is concerned.
3) Finally, I suspect I may need to change my Dictionary<string, BasePage> class to a custom implementation that implements some sort of INotifyPropertyChanged but for Collections? Observable Collection is the term I am looking for, I believe.
I hope someone is able to bridge the gap in my understanding of WPF (property) internals; I would very much appreciate it. A basic sample would be even better, but if it is too complicated, just a nudge in the right direction will do. Thank you. :)
It's been a while since I solved this, and while I cannot remember the exact cause of the problems, there were a few different issues that made up the bulk of the trouble I ran into.
I ended up making the Property in question a non-abstract DependencyProperty in the base class; it was the only way in which I could properly delegate the change notifications to the interface. Derived classes simply ended up binding it to their controls (with a proper Converter in the case extra logic was necessitated).
As Dictionary<string, BasePage> does not support any sort of change notification, I made an extra collection of ObservableCollection<BasePage> which I used for binding purposes.
However, such a collection does not propagate a change event when items inside of it has a property changed. Since this situation required that, and I was binding to the collection itself in the context of a property that does not have a Master<->Detail relationship like a DataGrid (which basically add their own OnPropertyChanged handlers to the binded object), I ended up subclassing a VeryObservableCollecton<>. This one listens to its own items, and throws a proper change event (I think it was an OnPropertyChanged from the INotifyPropertyChanged interface) so that the binding (or in this case a multi-binding) would refresh properly and allow my interface to update.
It is hardly the prettiest code, and it feels over-engineered, but at least it allows me to properly bind the UI to the data in this manner.

Is it just me, or is WPF a mess of databinding and custom IValueConverters?

Seriously, it seems like every time I want to make my UI elements talk to each other, I end up coding a new, custom, IValueConverter :(. Someone tell me that I'm doing it wrong, please!
Examples:
I wanted a button to be enabled only if my textbox contained a valid URI. Great, time to code up a UriIsValidConverter!
Oh oops, I also wanted to disable it while I'm processing something. I guess now I need to code up a UriIsValidAndBoolIsFalseMultiConverter!
I want to display a list of files in a certain directory (specified by a textbox) inside a listbox. I guess I need a DirectoryPathToFileList converter!
Oh hey, I want icons for each of those files in the listview. Time for a FileInfoToBitmap converter!
I want my status to be red if my status-string contains "Error", and green otherwise. Yay, I get to code up a StatusStringToSolidColorBrushConverter!
I'm really thinking this isn't that much better than the old Windows Forms method of just wiring up everything manually using TextChanged events (or whatever). Which I guess is still an option. Is that what people actually do, perhaps, and I'm trying too hard to make everything fit into the databinding paradigm?
So yeah, please tell me if this is really how WPF coding is---or if I'm doing it wrong, and if so, what I should be doing.
Your approach is perfectly valid (though I would use a multibinding for the second example, rather than a such a specialised converter), though by placing all your logic into the XAML you are producing very high coupling between the way the application looks and the way that it behaves, because of this you may want to look into the MVVM pattern to separate those things out.
Under the MVVM pattern your XAML (the view) just contains very simple data bindings into a ViewModel which handles all the logic and updates the view through the INotifyPropertyChanged interface. The code for your third example may look something like:
public class DirectoryManagerViewModel : INotifyPropertyChanged
{
private string _directory;
public string Directory
{
get { reutrn _directory; }
set
{
if (_directory != value)
{
_directory = value;
OnPropertyChanged("Directory");
if (IsValidDirectory(value))
{
PopulateFiles();
}
}
}
}
public ObservableCollection<FileViewModel> Files { get; private set; }
private bool IsValidDirectory(string directory)
{
//return if the directory exists etc.
}
private bool PopulateFiles()
{
//Populate Files with files in directory
}
}
Where FileViewModel is another view model which contains the name and the icon for a file.
The advantage of this approach is that the ViewModels can be reused with other views and other technologies such as ASP.NET or Winforms so you are not locked into the WPF stack. (alos if you work in an environment where there are designers responsible for the look and developers responsible for the behaviour, this helps define those boundaries)
At the end of the day though this logic does need to go somewhere and while there are better and worse ways to architect your application you are still going to be writing code that takes a string and converts it into a series of filenames and icons somewhere.
First, you might want to start by reading about the Model-View-ViewModel pattern (MVVM). Josh Smith had a fantastic article in MSDN Magazine recently. MVVM and WPF go perfectly together. Done right, you won't need IValueConverters so much. The way that you are going about it now is causing a very tight coupling between your visualization and your application actions. MVVM is designed to decouple these elements.
In this context, your view model will track state for you. Your button will be enabled if the CanExecute method on a certain ICommand in your view model returns true. This same concept can handle disabling the button when processing something.
You want to display a list of files in a certain directory that is specified inside a listbox? Have a DirectoryViewModel view model that will handle providing the list of files to the view by binding to the view model. The display of the files can be specified with a DataTemplate specified in XAML with no code behind. This same concept can handle providing the icons to the view whose display can be specified in the template.
You want your status to be red if a status message contains "Error" and green otherwise? Let a view model handle determining the state and let the view bind to that state and now you only need an IStateConverter to convert the state to red or green appropriately (this is one of many ways to handle this problem in the MVVM context).
Get in the habit of keep data and state separate from your view and your applications will be loosely coupled, easier to design and maintain, and easier to test.
Don't know if you are wrong, just making it a lot harder than it has to be!
I use MVVM, so where you are writing customer converters, I provide a bindable property on the view model that tells the view what to do. For example:
To display a list of files, I provide a collection that contains that list.
If I want icons the object in that collection has a icon property
If I want a status to be red or green I provide a StatusColorbrush property.
By moving this logic into the view model, I get:
much simpler Xaml.
can test my view logic without the view.
This approach uses one of the strong points of WPF, it's binding capabilities.

WPF: LostFocus event on a particular control/view/viewmodel

I'm working in WPF using the MVVM pattern, and generally things seem to be working pretty well, as I wrap my brain around the nuances of both WPF and MVVM. However, I'm currently stuck on a particular issue. My actual application is fairly complex, so to simplify, let's take Josh Smith's near-defining article on the pattern and use the application therein.
Consider Figure 2, and imagine that the user has typed some stuff in the first and last name fields. Then the user clicks away from the workspace (viewmodel) entirely, either by clicking a different customer tab, or possibly a completely different viewmodel in the same application. In this case, what I'd like to have happen is for the application to ask "Hey, did you want to save your changes? Yes/No/Cancel" and respond appropriately. This has presented... challenges.
Because I'd like the user to be able to 'cancel' that first-pass suggests needing PreviewLostKeyboardFocus (since I could set Handled=true and cancel the focus shift). However, several user actions (such as clicking the tab of a different workspace) don't shift keyboard focus. LostFocus covers me better in that respect, but that's only after the focus has already been lost (though of course I could switch it back?) and there are issues with determining if the event was from the view itself (i.e., we're leaving the whole view) or if it's simply bubbled up from some contained object.
And big picture on all this - this seems to be an issue for the view, but then that implies writing code in the view rather than the magic viewmodel. Which makes me think i'm not looking at this correctly.
So I'm hoping I'm missing some big conceptual a-ha that will make all this clear. Help?
You need to concentrate on your model rather than your view. That is, what does change that should trigger your logic? In this case, I'd say it's when an attempt is made to change the active tab.
So you need an overarching view model whose responsibilities are:
Expose a collection of all sub view models (each of which appears in its own tab)
Track the active (selected) sub view model (ie. the active tab)
Your view would bind to these properties in the usual way:
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}"/>
The SelectedTab property would apply your logic as follows:
Is the current tab dirty?
If so, prompt the user via a service
If the user cancels, don't change the active tab
If the user saves or discards changes, then change the active tab
I think the key thing you're missing is the overarching view model. Working your way through my ActiveAwareCommand sample project may help increase your understanding.

Resources