So, I'm looking forward to create a simple layout in Caliburn.Micro, but I'm a little confused about how things are intended to be done.
The target layout looks something like this:
_______________________________________
| | |
| | |
| | |
| NAV | MAIN |
| | |
| | |
| | |
|___________|__________________________|
From what I'm reading on the many tutorials, there should be a root view model usually called Shell
which derives from a Conductor
and activates the Main
view using ActivateItem()
. So far, so good. But what if the Nav
is itself a view, not just some stack panel with buttons? I tried the following:
## ShellViewModel
public class ShellViewModel : Conductor<IScreen>, IShell {
private IScreen _navigationScreen;
public IScreen NavigationScreen {
get { return _navigationScreen ?? (_navigationScreen = new NavigationViewModel()); }
}
}
## ShellView
<Window...
<ContentControl x:Name="NavigationScreen" />
<ContentControl x:Name="ActiveItem />
</Window>
The navigation view gets loaded perfectly fine. But now I've got a few questions:
How am I supposed to signal e.g. the click on a button up to the
ShellViewModel
so it can change theActiveItem
? Through theEventAggregator
(really, broadcasting an event for all interested handlers just for a button?)?Why does the view model (
Shell
) need to care about the layout? Wouldn't it be better to have some kind of router for composition/layout stuff?What about dependency injection? Let's say the
NavigationViewModel
needs a file reader because it loads (I know, stupid example) it's navigational items out of a file? Since I'm creating it myself in theShell
, I need to have a reference to that dependency where it doesn't even belong. Or is theShell
some kind of god class that holds reference to every dependency just to pass them to the independent views?
I'm unfortunately unable to find any tutorials on Caliburn that go further than just baby steps and simple view composition, but from what I figured out so far, it all seems tightly coupled with no respect for DI etc. Or am I missing something?
DI is very available of course it is dependent on your container of choice, MEF, most samples feature it, SimpleContainer (baked in). There are Bootstrappers implimentations that are adapted for all other containers out there (StructureMap, Windsor, Ninject, etc), built in there is a static IoC class for getting to registered objects in the container outside of the bootstrapper, but I feel and some will say this as well that it has anti-pattern tendencies using it too much, use only when absolutely necessary.
To tell the views to switch for current actives, even though the sample is based on "dialogs"; Hello Screens does show how this is done cross viewmodel (ie shell to workspace) it is probably best answer to that bullet point
As for composition some will go with a custom conductor depending on the complexity you want. I tend to go with KISS method and only separate out in to modules when I feel it's worth it.
EventAggregator
is very handy for cross viewmodel communications. if you intend to use composition of courseConductor<>
is a good choice, view switching can also be implemented or a combination ofConductor
and multi-view single viewmodel designs.Inside your NavigationViewModel you would probably work with something like
IConductor
interface that would tell the Conductor on the Shell that there is a new active item to process..Just keep in mind that CM is viewmodel first primarily but does have the ability to do view first and is all in the configuration.. Choose one don't mix as a suggestion, mixing leads to weird behavior.
HTHs