One of the things that can hit you really hard when writing blog posts about open source software (like StoryTeller is), is the fact that your posts tend to get very fast outdated, especially when you don’t pay that much attention to the detail (like I did, sigh). If you’re not aware of what I’m talking about, it’s StoryTellers command story. I’m not sure when it changed but it definitely has changed and I needed to update my last post 11.2 quite a bit in order to reflect the changes. Today I would like to conclude my trip through StoryTellers UI infrastructure with a look at how Commands are integrated into the Screen Activation Lifecycle.
Some of my older posts on the topic showed that the component responsible for Screen activation and deactivation in StoryTeller is the
However, when the
ScreenConductor activates or deactivates a Screen, it delegates a major part of work to the so called
The only implementer of this interface, the
ShellService, is just a little facade around three things.
ICommandbar, which is the main toolbar of StoryTeller,
IOptionsMenu, which is a kind of Shortcut menu for StoryTellers Commands and
IScreenObjectRegistry, which acts as a store / front-end for the current Command registration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
You can see some interesting aspects in the short code above.
- The word transient appears several times. StoryTeller differentiates between two types of Commands: Permanent Commands and transient Commands. Permanent Commands are displayed, well permanently, while transient Commands are what I depicted as contextual Commands. They are Commands which should be only visible in a particular context.
- Contextualization of Commands is handled on a per Screen basis in StoryTeller. Every time a Screen gets activated or
IOptionsMenuget reset and completely rebuild. With this you can have a very different Command UI depending on which Screen is activated.
- The actual Command configuration in the Screen Activation Lifecycle is completely delegated to the active Screen. In his
Activate()method he receives a reference to the
IScreenObjectRegistrywhich can be used in order to start the Command configuration via a small fluent API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
The following code snippet shows an example of how this API could be leveraged inside a Screen.
1 2 3 4 5 6 7 8 9 10 11 12
Gabriel Schenker has written an excellent series on how to write such a fluent API. Although it’s targeting Silverlight, most of the involved problems are explained in detail there, so forgive me if I don’t dive into the actual DSL implementation.
Some final thoughts
Making the Screen responsible for setting up his Commands makes a lot of sense to me, since the Screen is the unit which gets plugged into the UI infrastructure and it also very likely plays the role of the Command receiver in terms of the classic GoF pattern description. This doesn’t necessary mean that Screens are the only place for Command configuration. The initialization of modules in a Composite application is also a very likely place for registration of permanent Commands.
I consider having a fluent API for configuring the Commands also a plus, because it IMHO makes the actual Command configuration a lot easier and accessible. I’ve used the same setup (fluent API + delegation to screen) on my last 3 projects and it always worked for me like a charm.
Like I mentioned in the previous post, what I don’t like that much is the idea of mixing in visual aspects (Icon, Size, Location) into the Command configuration, mostly because I’ve been burned by this in the past when facing complex menus, like the ribbon. I think it’s a good idea to externalize the visual aspect via XML, at least for all the static stuff.
This is it
This was the last post about StoryTeller (at least for a while). It has been an interesting voyage which taught me a lot about UI infrastructure design, StructureMap usage and Convention over Configuration. Although it was primarily my learning excercise I hope you took something interesting with you from this blog series, too.