Build your own CAB #14: Managing Menu State with MicroController’s, Command’s, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface

THIS ARTICLE IN ITS ENTIRETY IS HERE.

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn’t see anyway to write this post without straying into all of these different subjects.  When you try to write an explanatory article you have to walk a tightrope between a sample problem that’s simple enough to work through in no more than a handful of pages and a sample problem that’s just too simplistic to be valuable.  I’ll leave it up to you to decide which end of the spectrum this one falls on.  I also had a rough time trying to decide on the best way to order the topics in the narrative.  All I can do is ask you to scan the following headers if something seems to be missing or I’m lurching ahead.

Last week I had a flood of people follow Martin Fowler’s link into this series.  I thought it was pretty cool because most of my UI patterns material and terminology is transparently based on Fowler’s work.  I’m especially glad that Martin didn’t mention the fact that I volunteered to help with the UI patterns writing three years ago then disappeared…

If you missed something, here’s the Build your own CAB series in its entirety. 

  1. Preamble
  2. The Humble Dialog Box
  3. Supervising Controller
  4. Passive View
  5. Presentation Model
  6. View to Presenter Communication
  7. Answering some questions
  8. What’s the Model?
  9. Assigning Responsibilities in a Model View Presenter Architecture
  10. Domain Centric Validation with the Notification Pattern
  11. Unit Testing the UI with NUnitForms
  12. Event Aggregator
  13. Rein in runaway events with the “Latch”
  14. Embedded Controllers with a Dash of DSL
  15. Managing Menu State with MicroController’s, Command’s, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface (This Post)
  16. Replacing Data Binding with MicroControllers and the Window Driver Pattern – Forthcoming
  17. Subcutaneous Testing – Forthcoming
  18. Creating the Application Shell – probably a couple posts
  19. Wiring the Components with an IoC tool – Forthcoming, but I may push this off into late summer
  20. A Day in the Life of a Screen

The end is in sight.  In traditional developer style I blew the estimate for how long ”Build your own CAB” would take.  I thought all I needed to do was copy n’paste a bunch of verbiage and code from my DevTeach talks into Live Writer and that would be that – but my usual wordiness kicked in and I ended up submitting a completely new talk to DevTeach Vancouver on this subject. 

A couple years ago I remember reading Stephen King say that he always found the Dark Tower books difficult to write as a way of explaining why there was so much lag between new books, much to my exasperation at the time.  I’m obviously not Stephen King, and there’s no line of folks wrapped around the corner of CodeBetter waiting for the next installment, but I know how Stephen King felt now.  I do promise that the end of this series won’t be as shocking/disappointing/brilliant(?) as the end of the Dark Tower.*

 

Problem Statement

Again, I am not a licensed namer of patterns, and some of the people I’ve shown this code to have commented that it’s reminiscent of Smalltalk UI’s, so it’s a good bet that some of you have already seen or used similar approaches.  That said, I use the term “MicroController” to refer to a controller class that directs the behavior of a single UI widget.  By itself, a MicroController isn’t really that powerful, but like an army of ants, a group of MicroController’s working cooperatively (with some external direction) can accomplish powerful feats. 

Here’s a common scenario: 

  1. You have a menu bar of some sort or another in the top strip of your composite WinForms application
  2. Each individual menu item needs to fire off a command of some sort (duh)
  3. The availability of some, but not all, menu items is dependent on user roles.  In other words, some menu items will be disabled or hidden if a user does not have a necessary role.
  4. The availability of some menu items is dependent upon the screen that is currently active in an application with some sort of MDI or tabbed interface
  5. The menu bar frequently collects new additions as the application grows

There’s nothing in that list that’s particularly hard or even unusual, but I want to explore an alternative approach.  Off the top of my head, I’ve got four goals in mind for the design of my menu state management:

  1. Quickly attach the proper commands and actions to each MenuItem.  This can get tricky because each MenuItem potentially touches and interacts with very different pieces of the application. 
  2. Eliminate duplicate grunge coding.  I say you pursue any chance to eliminate the mechanical cost, and there’s quite a bit of repetitive functionality here.
  3. Make the code that specifies the menu behavior as expressive and readable as possible.  This code is going to frequently change, so it’s worth our while to make this code readable. 
  4. I want an easy way for each screen to configure the menu state, and I want this menu state calculation and manipulation to be as easy to understand, write, and test as possible.   

Much like the screen state machine sample from my last post, I’m going to try to use a Domain Specific Language (DSL) / Fluent Interface to express and define the menu behavior.  By hiding the mechanics of menu management behind an abstracted Fluent Interface I’m hoping to compress the code that governs the menu state to a smaller area of the code.  I want to be able to understand the menu behavior by scanning a cohesive area of the code.  It’s my firm contention that this type of readability simply cannot be accomplished by using the designer to attach bits and pieces of behavior.  Leaning on the designer will scatter the behavior of the screen all over the place.  One of the main reasons I don’t like to use the designer or wizards is because you often can’t “see” the code and the way it works.

Start with the End in Mind

Before zooming in one the individual components of the solution, let’s keep the man firmly behind the curtain and look at my intended end state.  Inside some screen (probably the main Form) is a piece of code that expresses the behavior of the menu items like this fragment below:


        private void configureMenus()
        {
            _menuController.MenuItem(openItem).Executes(CommandNames.Open).IsAlwaysEnabled();
 
            _menuController.MenuItem(saveItem).Executes(CommandNames.Save)
                .IsAvailableToRoles("BigBoss", "WorkerBee");
 
            _menuController.MenuItem(executeItem).Executes(CommandNames.Execute)
                .IsAvailableToRoles("BigBoss");
 
            _menuController.MenuItem(exportItem).Executes(CommandNames.Export);
        }

And in each individual screen presenter you might see some additional code to set screen-specific menu settings like this that would be called upon activating a different screen:

 

    public class SomeScreenPresenter : IPresenter
    {
        public void ConfigureMenu(MenuState state)
        {
            state.Enable(CommandNames.Save, CommandNames.Export);
            state.Enable(CommandNames.Execute).ForRoles("SpecialWorkerBee", "BigBoss");
        }
    }

So what’s going on here?  There isn’t a single call in this code to MenuItem.Enabled or any definition of MenuItem.Click, so it’s safe to assume that there’s somebody behind the curtain.  So, what is the man behind the curtain?  Before I talk about each piece in detail, here’s a rundown of the various moving parts:

  1. A small MicroController object for each MenuItem that “knows” when to enable or disable its MenuItem and set up the MenuItem’s Click event.
  2. A controller class for the menu that aggregates all of the MenuItem controllers.  Part of the responsibility of the Fluent Interface configuration code above is to associate a MenuItem with a CommandNames key so we can quickly reference the correct MenuItem’s when a different screen is activated.
  3. A series of Command pattern classes that all implement a common interface. 
  4. StructureMap is lurking in the background as my IoC tool of choice to wire the various parts together.
  5. The Fluent Interface configuration API.  For the most part, it’s job is to look pretty.  All it’s doing is gathering in input values to set on the individual MenuItem controller classes that do the real work.  What I’ve found so far is that Fluent Interface strategies seem to lend themselves best to situations like this where you’re really just configuring an object graph to do the real work.
  6. A MenuState object that is used to transmit the desired state of the menu from the individual screens to the main menu controller
  7. Each Presenter in the application implements a common interface that includes some sort of hook to configure the items on the main Menu.
  8. The whole application is stitched together with the combination of an ApplicationController and ApplicationShell.  I’m going to be very brief on these two because I’m going to devote a couple posts later down the line to these classes.

 

NEXT, LET’S LOOK AT THE PRESENTER PIECE…           …it’s all written, but Community Server wouldn’t let me post it all at one time for some reason.

 

 

 

* Come on, I’m not the only person that screamed and threw the book across the room when Roland ends up back at the very beginning.  I’m going to swear off fantasy books permanently if Rand doesn’t win a clear cut victory in book 12 whenever that comes out.  Almost 20 years worth of waiting better come with a really solid ending.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Build your own CAB, Design Patterns, StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Johan Samyn

    Jeremy,
    The link in all uppercase at the top does not lead to the article.
    Could you correct it please ?
    Regards,
    Johan

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Stu,

    I’ve liked every book in the Malazan series a little better than the one before. When I was in Montreal this spring I meant to get to the bookstore to try to get some of the later ones that haven’t made it to the US yet but didn’t get time.

  • Stu

    I’ve been following these posts with great interest – I for one appreciate the effort going on here.

    Completely off topic – but I fully agree with your views on the Dark Tower/WoT.

    If you’re after a new best series, try “The Malazan Book of the Fallen” – delivers a lot more than Jordan, Goodkind and Wurts (though that won’t stop me reading them all).

    Funny how after all your brilliant posts, the thing that causes me to comment is the fantasy novel critique :)

  • Patrick

    Oh c’mon, there is a line of folks waiting for your next chapter! And I’m sure I’m not the only one around. So, get the server going! :-)

    A solid client architecture is so important but imho not much work has been done here. We have so much development going on in the business or database tier. But with the client it’s like we have hundreds of MVC frameworks but not really a strategy for building a maintainable client. So, your interesting series of articles shows problems and solutions to this. I really appreciate it!

    And yes, the end of the Dark Tower sucks. It’s not the worst ending I’ve ever seen, but it feels much like an easy escape. Anyway the whole series is just brilliant and the ending can’t take this away. Ah, sorry for my English…do I make sense?