{"id":86,"date":"2008-08-05T20:42:24","date_gmt":"2008-08-05T08:42:24","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=86"},"modified":"2009-08-07T14:13:58","modified_gmt":"2009-08-07T02:13:58","slug":"multicast-events-part-1","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/86\/","title":{"rendered":"Multicast Events &#8211; Part 1"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>I remember one of the things that got me excited when I first read about the as-then new fangled C# and .NET stuff coming out of Microsoft was the idea that a single event could have multiple handlers.<\/p>\n<p>Cutting a long and irrelevant story short, my interest in .NET waned, although my interest in multicast events did not.\u00a0 For a long time I was resigned to having to do without them, but then realised that this was a self imposed penury.<\/p>\n<p>So I got out my jail breaking toolkit (Delphi) and set about tearing down the walls of my prison.\u00a0 And here&#8217;s how I did it&#8230;<\/p>\n<p><!--more--><\/p>\n<h3>Just To Tease You<\/h3>\n<p>Before picking apart the implementation, I shall first demonstrate some of the benefits that my multicast implementation has brought to my own projects.<\/p>\n<p>The juicy stuff &#8211; how it all works and, eventually, a link so you can download and use it yourself &#8211; will come later.<\/p>\n<p>So first, the basics &#8211; adding and removing handlers for an event.  I shall use a button class that supports a multicast version of the usual OnClick event.  In my own use, I distinguish between unicast and multicast events by naming multicast events with an underscore following the conventional &#8220;On&#8221; prefix.<\/p>\n<pre class=\"delphi\">  procedure TSomeObject.CustomClickResponse(Sender: TObject);\r\n  begin\r\n    \/\/ Some additional handling of an event...\r\n  end;\r\n\r\n\/\/ Adds my custom click handler to a button's On_Click event\r\nfButton.On_Click.Add( CustomClickResponse );\r\n\r\n\/\/ ... and this removes it again\r\nfButton.On_Click.Remove( CustomClickResponse );<\/pre>\n<p>When adding a handler to an event that may already have a handler, this conveniently does away with all the business of remembering the previous handler reference, remembering to call that previous handler at the end of the new processing and (hopefully) remembering to restore the old handler if we subsequently wish to remove our additional handler.<\/p>\n<p>Another thing that is often needed with event handlers is to disable an event while some processing takes place, usually in response that event itself.\u00a0  For example if we wish to modify the contents of an edit control and do not want any Change event to fire while we do so, ordinarily this will involve something like:<\/p>\n<pre class=\"delphi\">  var\r\n    oldChangeHandler: TNotifyEvent;\r\n  begin\r\n    oldChangeHandler := fEdit.OnChange;\r\n    fEdit.OnChange := NIL;\r\n    try\r\n      \/\/ Change edit control content without triggering change event\r\n      fEdit.Text := 'Some New Value';\r\n    finally\r\n      fEdit.OnChange := oldChangeHandler;\r\n    end;\r\n  end;<\/pre>\n<p>With my multicast events I can simply disable the event itself:<\/p>\n<pre class=\"delphi\">  fEdit.On_Change.Enabled := FALSE;\r\n  try\r\n    \/\/ Change edit control content without triggering change event\r\n    fEdit.Text := 'Some New Value';\r\n  finally\r\n    fEdit.On_Change.Enabled := TRUE;\r\n  end;<\/pre>\n<p>One problem that can easily crop up is what happens if a handler is added to an event and then the object that implements the handler get&#8217;s destroyed?  The next time the event fires an error is likely to occur when the handler on the destroyed object is invoked.<\/p>\n<p>My implementation even copes with this, and does so largely transparently.  There is a <em>little<\/em> work involved but really not much, requiring the implementation of an interface with a single method on classes that implement event handlers.\u00a0 The details of which I will go into when we delve into the implementation of these events themselves.<\/p>\n<p>Speaking of which, using these events is clearly quite straight-forward but what about implementing support for the events themselves?<\/p>\n<p>Well, that too is very straight-forward.<\/p>\n<p>A base class provides the basic behaviours needed &#8211; managing the list of handlers for the event and the enabled\/disabled state of the event.<\/p>\n<p>A specialisation of this class is needed for each event signature for which I want to have multicast support.\u00a0 In practice I have found that a multicast version of TNotifyEvent covers the vast (and I mean <em>overwhelmingly vast<\/em>) majority of cases where multicast events are useful.\u00a0 Not every event type is going to have a useful existence in a multicast form.<\/p>\n<p>These specialisations are fairly trivial, as we shall see when we come to them in future posts.<\/p>\n<p>I shall go through the step-by-step building up of functionality and features in the framework as it exists today &#8211; it won&#8217;t take long, amounting to less than 900 lines of code in all, including copious documentation (I use Doc-o-Matic, so an investment in well documented code pays dividends in usable reference documentation later).<\/p>\n<p>For now, one last piece of groundwork&#8230;<\/p>\n<h3>Anatomy of a Method<\/h3>\n<p>What exactly is a Method?\u00a0 Let us consider the hopefully familiar TNotifyEvent:<\/p>\n<pre class=\"delphi\">TNotifyEvent = procedure (Sender: TObject) of object;<\/pre>\n<p>This immediately highlights the difference between an event procedure type and regular Pascal procedure types &#8211; that innocuous &#8220;of object&#8221;, signifying that a method can only satisfy this type signature if it is some method of a class.<\/p>\n<p>Under the covers a reference to a handler for this type of event is required to identify not one, but two things:<\/p>\n<p style=\"padding-left: 30px;\">1. The method to be executed<\/p>\n<p style=\"padding-left: 30px;\">2. The object instance that the method is to be execute on<\/p>\n<p>That 2nd item of information of course ends up being the &#8220;self&#8221; that the event handler code may reference. For the most part, the details are taken care of by the compiler and the runtime.\u00a0 The Delphi runtime library even defines a type encapsulating a method reference, though you may never have come across it as ordinarily it has very limited use on its own:<\/p>\n<pre class=\"delphi\">TMethod = record\r\n  Code, Data: Pointer;\r\nend;<\/pre>\n<p>And believe it or not, armed with this knowledge we now have all we need to implement our multicast events.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> I remember one of the things that got me excited when I first read about the as-then new fangled C# and .NET stuff coming out of Microsoft was the idea that a single event could have multiple handlers. Cutting a long and irrelevant story short, my interest in .NET waned, although my interest in multicast [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[25,26],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-1o","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":160,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/160\/","url_meta":{"origin":86,"position":0},"title":"MultiCast Events &#8211; Conclusion","date":"11 Aug 2008","format":false,"excerpt":"Drawing this subject to a close (finally!), here's the concluding post I promised, including the fully documented and finished implementation that has been serving me well for almost 2 years.\u00a0 The finished implementation incorporates a number of refinements to the core framework, and those are what we shall briefly look\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":112,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/112\/","url_meta":{"origin":86,"position":1},"title":"Multicast Events &#8211; Video Demo 1","date":"07 Aug 2008","format":false,"excerpt":"My second post on multicast events is now up, and here's a video showing the basics. It was also an excuse to get to grips with the video capturing software - CamStudio - (and technique!), which proved to be a frustrating exercise to say the least, but I am quite\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":137,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/137\/","url_meta":{"origin":86,"position":2},"title":"Multicast Events &#8211; Part 3","date":"09 Aug 2008","format":false,"excerpt":"So far we've seen a multicast event implementation in (fairly limited) action, and dissected the core of it's implementation, which was a fairly dry affair. I also demonstrated a flaw in the initial implementation - a susceptibility to objects adding handlers to events but not removing them when being destroyed.\u00a0\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":147,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/147\/","url_meta":{"origin":86,"position":3},"title":"MultiCast Events &#8211; Video #2","date":"09 Aug 2008","format":false,"excerpt":"At the end of my last post I described a problem that arises if an object adds handlers to an event and is then destroyed without having removed those handlers.\u00a0 This video demonstrates that problem and also shows a solution provided by the multicast events framework itself. The details of\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":102,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/102\/","url_meta":{"origin":86,"position":4},"title":"Multicast Events &#8211; Part 2","date":"07 Aug 2008","format":false,"excerpt":"Having covered some of the basic use of multicast events, in this second post I shall start to build the implementation.\u00a0 In this first iteration we will provide the basics of a multicast event - managing and calling multiple handlers and the ability to enable and disable an event. The\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":180,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/180\/","url_meta":{"origin":86,"position":5},"title":"Latest Tibur\u00f3n Preview","date":"14 Aug 2008","format":false,"excerpt":"I was a little disappointed that the preview webinar this morning was little more than a re-run of the same content from a little over a week ago, albeit with some downloadable PowerPoint slides this time. It was at least an opportunity for some more Q&A and a couple of\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/86"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=86"}],"version-history":[{"count":6,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/86\/revisions"}],"predecessor-version":[{"id":465,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/86\/revisions\/465"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=86"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=86"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=86"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}