Jeremy Miller just published a post asking for feedback on how we activate and deactivate our screens in our application frameworks (what I also call a Presentation Framework). I started replying in the comments then realized it was going to be too long … so here is my reply to his post.
Sidenote: Prism itself is a library of tools that we can use in an application, but it is not a framework on its own. Prism is great in this sense since it allows us to choose what to use and when, as opposed to running how we do things.
I am writing an article series for MSDN on using Prism and Silverlight to build a LOB application that should be surfacing next month. So much of what I am saying here will be seen in detail in those articles. But here is a glimpse of what I will write about in more detail and show extensive code for.
I do not pretend that this is the perfect way or the only way … in fact, it is just a way that works well for applications that I have been involved in. Do I like it? Yes … but I am also always looking for improvements too. Hopefully this adds some value to Jeremy’s post.
I broke down my comments towards Jeremy’s post using the outline he created as a guide. He asked for feedback on specific topics, so here I go:
- - View 1st vs VM 1st -
I choose to have the Screen class coordinate the MVVM triad. This way I have can make marry the View to the ViewModel in the Screen without having to choose who gets created first. So I crank up the View, crank up the VM (using Unity for both), then associate them vie the View's DataContext. Yes, creating the VM in the View as a resource has Blend advantages, but its too tight for me. And injecting a View into a VM is fine, but again, the marrying process is looser, so I run with it.
- - Modularity -
I like to locate the generic components of the "Presentation Framework" in the Infrastructure project. This is where all generic classes go that help build my Silverlight, WPF, or whatever infrastructure. ScreenConductor, ScreenSet (within the ScreenConductor), IScreenFactory, IScreen, ScreenFactoryRegistry. I use Unity as my IoC to help crank these babies up in other Modules. works quite well. Then each Module uses an implementation of a ScreenFactory (which creates the Screen class ... which in turn coordinates the MVVM triad), gives it to the ScreenFactoryRegistry so it knows how to crank it up when needed.
- - Starting Screens -
I choose to crank up the MVVM triad from a Screen class. This Screen class is responsible for owning the Model, View and ViewModel … it also marries the V to the VM (which means I do not need to tightly couple my V to my VM nor vice versa) . This is an extra class, but it is very small and has a very distinct job.
Menus crank up screens by raising an event … or publishing an event. I choose to keep this very loose since you never know who might want to crank it up, or if multiple palces want to do so. This also makes it very easy to ignore if the screen does not exist yet (during dev).
When an event is published (using the Prism EventAggregator in my case but it could be done in any event oriented manner) my ScreenConductor class subscribes the the event, uses an argument from the event to find the ScreenFactory in question in a ScreenFactoryRegistry (all ScreenFactory’s are registered in their individual modules with the singleton registry), and then looks to see if the Screen is already active (but hidden), active (and visible), or not at all active. Depending on the state, the screen is then shown (or activated first if needed). All activated screens are stored in a ScreenCollection/ScreenSet so the ScreenConductor can find them.
- - Closing Screens -
I can choose to tell a Screen to close or to hide itself. If i tell it to hide itself, the ScreenConductor handles that work easily removing it from visibility but keeping it in the ScreenCollection. If I tell it to close (event driven), the ScreenConductor kills the Screen and its family (MVVM triad) off. I tell screens to close or deactivate … I do not believe a Screen should know which to do.
- - Close All, Close Some, Close 1, Etc. -
Closing all screens is done by the ScreenConductor if an event is published for it and it receives it. It knows about all screens, so it can easily close them all. Deactivate all is the same process. The event can be published with the knowledge of close all but this one or close this set of screens, too. Each screen has a ScreenKey (usually a string or an enum) … some identifier so we can manage this process.
- - Dashboards -
Prism is great for this … the regions make it simple to load screens into them and make a dashboard effect. This is one place I have started to look at the process of identifying which region a Screen should be thrown into. Should the Sorting Hat tell the Screens where to load (the Sorting Hat being the events) or should this be identified in another way. Right now I am still debating on this topic as I have done it a few ways all of which have ups and downs.
OK, so I was a bit long winded here …. but man it’s a fun and involved topic! I’ll clarify, expand, and show tons of code in my upcoming articles. I welcome feedback and discussion. What Jeremy Miller, Glenn Block, Ward Bell and others are doing with presentation Frameworks is timely and exciting. We all seem to be going down the same path, taking branches and diversions along the way, but to the same end … a solid Presentation Framework to manage “screens”.