I hope you’ve found this little journey helpful. It was definitely a fun “let’s get re-acquainted” experience for me!
A few final thoughts and takeaways:
The Microsoft-supported MVVM toolkit is very powerful and quite elegant. But the documentation is sometimes problematic1. Particularly when it comes to the messaging subsystem. I found that portion so difficult to comprehend I finally threw up my hands, crossed my fingers, and used the "default/simple" approach mentioned briefly in the docs. Fortunately it worked, and even more fortunately it covered my entire use case.
Do use dependency injection and do consider implementing some way of having your dependency injection system be aware of whether it’s being called at design-time or at run-time. Whether or not you use J4JViewModelLocator is up to you — doing so will require you to buy into other parts of my personal development environment which you may not wish to do. But some design-time/run-time awareness in your dependency injection system makes things much easier.
Keep your viewmodels ignorant of each other’s existence. I didn’t do this initially — because I hadn’t yet figured out the toolkit’s messaging system2 — and, while my earlier approach worked, it wasn’t clean. Worse yet, it made it difficult for me to keep track of what I was doing in different parts of the codebase. Ignorance is bliss in this case. Learn to use the toolkit’s messaging system.
Embrace the behaviors add-on package. You can avoid using it by creating simple Net event handlers in a UI element’s code-behind which, in turn, trigger methods in your viewmodel3…but that’s convoluted. Admittedly, the XAML code to "simply" map a UI event to a RelayCommand is convoluted itself. But XAML ain’t known for its terseness :). And with the behaviors approach you’ll do all action-processing the same way, by means of RelayCommands. Consistency is your friend in writing software :).
Remember to display compiler build warnings, at least occasionally. By default I usually turn them off because I get a lot of warnings early on which I go back and fix4. But WPF, by design, absorbs/suppresses a lot of things you ought to know about…many of which5 will show up as build warnings.
Debugging design-time problems is counter-intuitive. You’re already in a debugging environment, why do you need to create a new one? But an XAML design window actually runs a lot of your codebase behind the scenes…and if there are bugs there you may see some strange things displayed. Or, more likely, not see them displayed, because WPF absorbs most such problems6.
The workaround is to launch another instance of Visual Studio and attach the debugger to the WPFSurface.exe process running in the instance where you’re developing your app. You can then set design-time breakpoints and walk through your code at design-time. If you don’t see WPFSurface.exe it’s probably because you haven’t yet opened up an XAML designer — it’s only launched as needed (although the second Visual Studio instance will keep it from being closed by the first one).
Remember to include Dispatcher.Yield() calls at appropriate places in your code to allow the UI thread to update the UI.
that may be due to my own level of ignorance, of course ↩
there’s that documentation issue again :) ↩
that’s what I was doing before I stumbled across the package ↩
or suppress if I know the warning won’t be a problem ↩
at least the XAML-related ones, in my experience ↩
you can usually find them cited in the output window. But who wants to spend their time reading through the output window? :) ↩