Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to conduct multiple windows in Caliburn Micro?

I am working on an app using Caliburn.Micro. I need to open a set of identical windows on multiple monitors at once, and I cannot figure out how to do this cleanly.

My idea is this:

  • ChildViewModel / ChildView contains the things I need to show on multiple screens.
  • ParentViewModel inheriting from ConductorBase<ChildViewModel>.
  • When ParentViewModel is created, it creates the required number of ChildViewModel and uses WindowManager.ShowWindow to show each of them.
  • My WindowManager implementation takes care of placing these views where they are supposed to be.

All of the above works, with one exception: the ParentView is displayed in its own window. How can I avoid this happening? what would be the canonical way of doing what I am trying to do?

What I want to do is conduct multiple windows from a single conductor, without the conductor itself showing a window.

like image 702
Vegard Larsen Avatar asked Aug 06 '15 07:08

Vegard Larsen


1 Answers

What about this schema?

                          SystemTrayVM
      (VM for your notification area, its View is the sys tray icon)
                                |
                                |
                      MultipleDesktopManager
      (not a VM, not a ConductorBase, no View, not visible)
                                |
            .-------------------|------------------.
            |                   |                  |
            |                   |                  |
    SingleDesktopVM      SingleDesktopVM     SingleDesktopVM
(its View holds child views. If necessary, it can be a ConductorBase)
                                |
                  .-------------|------------.------ - - - .
                  |             |            |
                  |             |            |
         SideBarChildVM    MainChildVM   FooterChildVM
  • SystemTrayVM is responsible for all interaction made available through the notification area (right click menu action, etc.). It would not actually open/close the windows visible to user, but rather forward those commands to the MultipleDesktopManager.

  • MultipleDesktopManager is not visible and is not a VM. Its responsibility is to e.g. open/close all single desktop parent windows when needed. Being completely separate windows, there should be no need for a full blown conductor. From my experience, it is enough to provide it with an IWindowManager so that it can actually show/close the single desktop parent windows. Maybe it could also activate/deactivate them, but no need to keep track of a current active item or things like that.

  • SingleDesktopVM is responsible for all the child views/VMs shown inside itself. So this could be a conductor if needed... it really depends on the lifecycle of those child views inside the parent. E.g. if there's a command-bar and a main content and they're always there, probably you could go with a simpler parent VM containing other VMs.

In a recent past we faced & solved the issue of a WPF application starting not visible, only found in system tray, and from there being able to show/hide the actual main application window.
In that scenario, we offloaded the task of hiding/showing the main app window to a helper class (not a VM) invoked by the SystemTrayVM. That would be the equivalent of MultipleDesktopManager in this schema.

Regarding the WPF application starting from system tray only, we put together a PoC on GitHub that shows how to completely integrate this WPF NotifyIcon control with a Caliburn.Micro ViewModel-first approach and DI through Autofac.

EDIT: The rationale is that Conductor implementations offered off the shelf by CM seem more adequate for a window holding other child windows. If the holder is not itself visible, maybe those conductor implementations are not the perfect choice. As you said in comments, it's like needing a Conductor not being also a Screen. There's an interesting bit on CM composition doc page about "Quasi-Conductors". In the end, the MultipleDesktopManager idea is basically that of a simple conductor that manages many windows, without implementing the IConductor interface but still using the WindowManager in order to process SingleDesktopVMs lifecycle correctly.

like image 58
superjos Avatar answered Nov 01 '22 17:11

superjos