I’m working on a throwaway application, but I like to use these as a chance to sharpen my skills with unfamiliar things. So I decided to use MVVM and WPF instead of sticking to my WinForms comfort zone. I can’t figure out how to make some pieces of my UI talk to each other. Well, it’s more like I can’t find a way to do it that doesn’t seem wonky.
The application’s testing performance of an algorithm for determining the minimum/maximum of slices out of a large data of collection. Here’s what it looks like.
The main window’s ViewModel generates a collection with many values. I want to specify a range for a slice, then execute several versions of minimum/maximum algorithm to verify correctness and execution time.
The parts in group boxes at the bottom are two instances of a UserControl I’ll call the child controls. This made sense to me because I knew I’d need several and didn’t want to copy/paste clusters in the main window. This is where the trouble occurs.
The main window VM has properties for the collection and the slice range. I need the child VMs to have access to these properties. This is proving difficult. Ideally, I’d want something like this:
<local:AlgorithmTester RangeStart="{Binding RangeStart}"
RangeEnd="{Binding RangeEnd}"
Values="{Binding Values}" />
The child VMs have their own VM. If I put dependency properties on the control, I have to link those properties to the control’s VM as well, probably through an in-code binding. This seems kind of wonky to me. I’ve thought of the following alternatives, but all seem kind of strange to me:
- Don’t use UserControls; copy/paste the code for each tester.
- Set up the VMs for the testers in code in such a way that a lambda can capture the needed properties in a closure. (Doing this right now.) This makes me feel dirty as the lambdas should belong in another class.
- A Twitter friend suggested an event aggregator. The child VMs would subscribe to a “RangeStartChanged” aggregated event (and others.) I don’t like this because I feel the relationship between child VM and parent VM should be more clear; maybe it’s old habits dying hard?
- Instead of a UserControl, use a templated ItemsControl against a class with the appropriate properties. I’d still have to find a way to communicate changes in the main VM properties, but that’d be logic internal to the main VM. The only reason I don’t like this approach is it strikes me as odd; this could be years of WinForms experience holding me back. (The more I think about this one the more I like it.)
Are there other solutions? Am I being too picky about the ones that exist? What would you do?
I would personally either make them UserControls with dependency properties, and bind them in your main view model as shown. Alternativley, and what I would actually do, is use an MVVM framework such as Caliburn.Micro which makes view composition incredibly easy.
In Caliburn.Micro’s case, you would have 2 public properties on your main view model, each of type
AlgorithmTesterViewModel, and on your main view 2ContentControl‘s called the same as your 2 public properties.Caliburn.Micro will automatically locate the
AlgorithmTesterViewby naming convention, inject the view into the 2ContentControl‘s (via DataTemplates behind the scenes), and bind up the controls on each to the properties on theAlgorithmTesterViewModel.You would then instantiate the two
AlgorithmTesterViewModel‘s in your main view model, passing in the appropriate data, and assign them to the 2 public properties.By the way, you look a lot like David Mitchell. That is neither an insult or a complement. Just an observation of fact.