CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

Build your own CAB #12 - Rein in runaway events with the "Latch"

Wow, an even dozen, and I've still got a ways to go.  Just to prove that I can write a short post, this one is brief (because it was meant to be a little section in the Event Aggregator post). 

A couple people have asked for a PDF of the series when it's done.  I'll do my best to stitch it together and just slap it up on CodeBetter somewhere.  In the meantime, here's the predecessor posts in the series:

 

  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" (This post)
  14. Embedded Controllers - Forthcoming
  15. MicroControllers - Forthcoming
  16. Subcutaneous Testing - Forthcoming
  17. Creating the Application Shell - probably a couple posts
  18. Wiring the Components with an IoC tool - Forthcoming

The "Latch"

In the last post I talked a little bit about runaway events in a fat client.  One event causes an action that changes another control which conceivably fires another event which eventually sends you application spiraling out of control.  All because a little bug went Kachhhoooooo!  What we need to do is ignore or turn off an event handler while a certain action is taking place.  You could just temporarily detach the event handler while you're performing that action like this code:

 

            // Remove the event handler for the moment

            _someComboBox.SelectedIndexChanged -= new System.EventHandler(someHandler);

 

            // do something that would probably make _someComboBox fire the SelectedIndexChanged event

 

            // Put the event handler back

            _someComboBox.SelectedIndexChanged += new System.EventHandler(someHandler);

 

It works, but I wouldn't want to do it everywhere.  It's tightly coupling the code inside this method with the rest of the View.  I would bet that this approach would quickly make a View very difficult to modify. 

My preferred approach is what I call a "Latch" (it's taken from a pattern used in messaging to stop a message from endlessly cycling between two systems that publish events to each other).  Inside any method or logical operation that could cause cascading events you simply set the latch to mark an operation in progress.  In the relevant event handlers you first check to see if the latch is set, and cancel any additional actions in the event handler is the latch is indeed set.  It could be as simple as just tracking a Boolean field in a View class.  Slightly more sophisticated is something like the "Latch" class from StoryTeller:

 

    public delegate void VoidHandler();

 

    public class Latch

    {

        private int _count = 0;

 

        public void Increment()

        {

            _count++;

        }

 

        public void Decrement()

        {

            _count--;

        }

 

        public bool IsLatched

        {

            get { return _count > 0; }

        }

 

        public void RunInsideLatch(VoidHandler handler)

        {

            Increment();

            handler();

            Decrement();

        }

 

        public void RunLatchedOperation(VoidHandler handler)

        {

            if (IsLatched)

            {

                return;

            }

 

            handler();

        }

There isn't too much to the usage.  In the method that performs work you might do this:

 

            _latch.RunInsideLatch(delegate

                                      {

                                          // The actions that spawn cascading events

                                          activatePresenter(presenter, page);

 

                                          _tabControl.Items.Add(page);

                                          _tabControl.SelectedTab = page;

                                      }

                );

In an event handler effected by this work you could guard the event propagation by doing this

 

        void TabControl_TabSelected(object sender, TabEventArgs args)

        {

            if (_latch.IsLatched)

            {

                return;

            }

 

            ContentTab tab = (ContentTab) TabControl.SelectedTab;

            activatePresenter(tab.Presenter, tab);

        }

or this version (fun with anonymous delegates):

 

        void TabControl_TabSelected(object sender, TabEventArgs args)

        {

            _latch.RunLatchedOperation(

                delegate

                    {

                        ContentTab tab = (ContentTab)TabControl.SelectedTab;

                        activatePresenter(tab.Presenter, tab);                       

                    });

        }


I've used this pattern about 3-4 times with some success.  It's especially powerful in conjunction with an Event Aggregator.

So what did I really buy here?  In the application, opening a new screen involves the creation and activation of a new TabControl, which raises an event for selecting a new tab.  For tabs that are just inactive, I need an indication from the SelectedTab event of a TabControl to tell that particular Presenter to reactivate.  The SelectedTab event is necessary for screens that are already open, but nothing but trouble for creating a brand new Tab.  By setting a latch in the event that opens a new TabControl, I an easily ignore the SelectedTabl event just while the TabControl is being setup.

Is this really a design pattern?

I've used some derivation of this solution on at least four projects, so it's safe to say that it is *a* pattern.  Design patterns generally aren't anything terribly fancy, there just things that you do - repeatedly.  When experienced people learn design patterns I often hear some snorting to the effect of "I already do this."  Yes, that's kind of the point in calling it a "pattern." 

I'm not an officially sanctioned pattern naming body, so it's not necessarily appropriate for me to be making up the name here.  I'd bet anything that someone else has already described this pattern and I'm just not familiar with the named pattern.  If you've seen this written up somewhere else, please throw in a link in the comments.



Comments

Evan said:

This series of posts is *really good* stuff.. Thanks for taking the time to share.. ;-)

# July 2, 2007 8:50 PM

skware said:

It might be worth pointing out that most of that code is non threadsafe and in production would need to be made so.

# July 3, 2007 9:49 AM

Ayende Rahien said:

skware,

Not really. If you need to do explicit thread management, you have already lost. It is usually best left to the framework to coordinate that.

# July 3, 2007 10:48 AM

Martin Jul said:

Another interesting event handling pattern that I have used is a transacted event mechanism.

Assume that you have a graph of objects where each node has an ObjectUpdated-event. Observers subscribe to these events to display the graph.

Now, when the graph is being updated we encounter a number of problems - every time we update something in the graph we trigger the Observers  possibly triggering yet more events. Also, if the same node is updated by more than one operation during the graph update the Observers get invoked multiple times for the same object, and finally, the real issue is if the update operation is not atomic the graph is in an invalid state while the events are being raise.

Enter the transacted event latch.

We implemented this by basically using a latch-like approach to collect all the events that wanted to fire during the transaction in a transaction object, then when the transaction was completed, firing the queued up events (after eliminating duplicates to improve performance).

# July 3, 2007 2:14 PM

Jeremy D. Miller said:

Martin,

That's cool.  Thanks for the tip.

Jeremy

# July 3, 2007 4:07 PM

Jeremy D. Miller -- The Shade Tree Developer said:

Just to continue the world's longest run on sentence. Before I start, here's the table of contents

# July 6, 2007 12:40 PM

Sam Gentile said:

Multithreading and Concurrency Software Transactional Memory Part IV - Thread-Bound Transactions Software

# July 11, 2007 8:16 AM

Insane World said:

The

# July 11, 2007 10:16 AM

Ollie said:

Is this not just an implementation of a non blocking synchronisation mechanism at a event handler level?

# July 12, 2007 5:10 AM

Jeremy D. Miller -- The Shade Tree Developer said:

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn't

# July 24, 2007 5:18 AM

Jeff Lewis said:

One suggestion would be to make Latch implement IDispose.  The constructor would Increment and the Dispose method would Decrement.  This would help ensure that they always get called in pairs:

using (new Latch())

{

 ContentTab tab = (ContentTab)TabControl.SelectedTab;

 activatePresenter(tab.Presenter, tab);    

}

# July 24, 2007 10:16 AM

Jeremy D. Miller -- The Shade Tree Developer said:

Yes, this is overdue. Here is an introduction and table of contents to my "Build Your Own CAB"

# July 25, 2007 9:22 PM

Simon Jones said:

Great series. Can you let me know if you intend to cover best practices for form flow. There is probably a better term for this, but what I mean is the logic for deciding which forms to display and in what order.

# July 26, 2007 10:45 AM

Jeremy D. Miller -- The Shade Tree Developer said:

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn't

# July 26, 2007 10:57 AM

Jeremy D. Miller -- The Shade Tree Developer said:

After a bit of a hiatus and a fair amount of pestering, I'm back and ready to continue the "Build

# October 21, 2007 9:13 PM

Mark Lindell said:

One other improvement:  If an exception occurs during the delegate would want the latch to handle the decrement.

public void RunInsideLatch(VoidHandler handler)

       {

           Increment();

           try

           {

               handler();

           }

           finally

           {

               Decrement();

           }

       }

# November 7, 2007 10:12 AM

Jeremy D. Miller said:

Doh!  Nice catch Mark.

# November 7, 2007 10:14 AM

Jeremy D. Miller -- The Shade Tree Developer said:

To everybody that attended one of my talks at DevTeach this week. All of the materials are now online

# November 29, 2007 12:03 PM

ZeusTheTrueGod said:

Hi

I worked some times with same problem, for example two linked combobox(when you select something in one, second should select the same)

I prefer this model:

Each event test some field(same as IsLatched). When someone choose a value in combobox, the controller method is invoked, then presentation model is changed and method view.RefreshData is called inside RunLatchedDelegation.

In real application i have hierarchy of view and controllers,

so each parent controller can intercept any action of child controller, that allows user actions on one view to be visible on others

# July 6, 2008 12:56 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

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 previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP