In MVVM, we tend "not" want to couple windows to view models for various reasons. Though from the very second screen on your application you start hitting this conceptual grey zone.
You see viewmodals tend to want to open windows/Views (its just a fact of life). Windows/dialog APIs tend to like an Owner, because thats just the nature of the Windows Operating system. As can be seen here
When a child window is opened by a parent window by calling ShowDialog, an implicit relationship is established between both parent and child window. This relationship enforces certain behaviors, including with respect to minimizing, maximizing, and restoring.
This all creates a bit of a dilemma where Viewmodals are natively disconnected from their view/window hence you have to use some sort of decoupled messaging event aggregation, or some other logic to couple the dialog relationship.
At this point people use frameworks or other regimes which basically consist of weird and contrived world of DI/IOC, view constructors, locators, messages or event aggregation to do all the coupling, spinning up of viewmodals and so forth and keeping the MVVM police happy.
The current solve
In the current projects im working on, the principle developer has solved this problem with using typed decoupled messages (pub/sub), which gets picked up in a view constructor with an application wide view mapping regime that maps these messages to view to windows, converts and passes objects to the newly created view models through more messages in what can only be called more spurious plumbing, and at the end of the dialog lifecyles passes back out parameters back into the original typed message which can then be probed bythe original caller.
This is all very messy (IMO) overly complicated overly engineered and inadequacy designed.
I guess this where the notion of a dialog service comes in. A simple Fluent library that can use viewmaps or implicitly coupled commands to call, spinup windows.
// Modal Dialog no results _dialogService.Dialog<Window1Vm>(this) .OnInit(vm => vm.SomeProperty = false) .ShowDialog(); // Dialog with some results var someResult = _dialogService.Dialog<Window1Vm>(this) .OnInit(vm => vm.SomeProperty = false) .ShowDialog(); // Dialog with some input params var someResult = _dialogService.Dialog<Window1Vm>(this) .WithParams(new SomeParamsToPassIn()) .ShowDialog(); // And the one the "decoupled police" will be wanting to arrest me for // Dialog with explicit notation to map a view to a viewmdal // (I know i should be shot and fed to the wolves) var dialog1 = _dialogService.Dialog<Window1Vm, Window1>(this) .OnInit(vm => vm.SomeProperty = false) .ShowDialog();
My question is now, should this be an injectable service, or a static class
The advantages of an injectable service is that, ViewModals and code who need access to this, can just ask for it. Its easy to see who is implimenting this functionatlity via the constructor
The disadvantages is if you have lists of lists of vms and something in the child list needs to open a window you have to inject it into all the child viewmodals or once again send a message back.
The advantages of being a static class, is you can call it everywhere, kind of like a true UI cross cutting concern.
Personally i think the DI service is the way to go, it has no state logic i.e it can be a singleton. However i have had several comments about this approach (from mainly the principle developer) that messages are just better and it can be called from anywhere, also that static is bad mmkay.
However i just want to get opinions about if logic, like does this sit better as an injectable service, a static library, or in other peoples experience that might sugest having a totally decouple system like we have is actually a better approach in large systems and the long term