Favor ViewModels Over Converters
So in the little MVVM game app I’m building I need to display the game timer. First I exposed an Int property on my ViewModel called ElapsedSeconds which did the usual INotifyPropertyChanged stuff. In my ViewModel, I incremented this Property when my Timer ticked, I also zeroed it out and occassionally added large blocks of time to it for penalties when a player used the “hint” feature.
Next, I created a converter which took that integer value and converted it into an appropriate string value to display time in minutes:seconds format, or hours:minutes, depending on how long they were playing the game. Then in a TextBlock in my View I had a binding to the ElapsedSeconds property on the ViewModel and used my custom converter.
This worked, and I was reasonably happy with it–I even unit tested my converter and felt good about it.
But in the back of my mind I was still batting around the ideas about using ViewModels instead of converters. At first I disagreed with that approach. After all, why should the ViewModel care about the display format of their values, which seems to be a purely UI concern? Furthermore I had unit test coverage of my Converter so I could test my formatting logic. It didn’t make sense.
Then, for the heck of it, I decided to try it that way. I kept my ElapsedSeconds property on the ViewModel and added a property called ElapsedTime of type string. To keep change notification working for Bindings to this property I raise property changed in the setter of ElapsedSeconds which is the property that the ViewModel uses internally.
The best part is that the functionality to convert from an integer of seconds to a formatted string of “time” is now in an extenstion method I wrote for type Int32. The getter for ElapsedTime simply calls that extension method on the member variable which holds the number of elapsed seconds. The extension method can of course be fully unit tested just like the converter could, but it has requires less code both in the method itself andthe unit test class, because unlike a converter it is typesafe.
So, overall I think I like it better. There’s less “ceremony code” than there used to be in the extension method than in the converter (Int32.TryParse() calls with the value passed into the converter, and returning Binding.DoNothing for bogus inputs). I no longer have to have unit tests that passed in bogus values to the converter to make sure it would react appropriately–the unit tests can focus on only testing valid cases now since the extension method can only be called on Ints. That alone saved me quite a few lines of code.
Of course there is nothing preventing UI layer developers from building and using their own value converters in their bindings in XAML. The way I see is that the ViewModel offers up the “raw” format (seconds as integers) as well as a fancy format that will work in many UIs so that many UI developers wouldn’t have to write their own converter.
I still think there may be uses for converters. But I’m hard-pressed to think of any in which you have the ability to modify the ViewModel source.
At first I was uncomfortable with the idea of UI formatting or Focus change events (see Josh Smith’s blog) ocurring in the ViewModel because it seems to not be separating concerns appropriately. But I think the key is to remember that the ViewModel really is modelling a view.
Anyhow, that’s what is on my mind tonight.