<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8594690550975135798</id><updated>2011-08-24T20:48:20.171-07:00</updated><category term='AppDomain'/><category term='Mutex'/><category term='Azure Fast Deployment Web Deploy'/><category term='VC++ Runtime'/><category term='IDisposable'/><category term='git'/><category term='Xml Serialization with custom collections'/><category term='HyperV perf issues'/><category term='Open Spaces'/><category term='App Isolation'/><category term='remoting'/><category term='Data Binding'/><category term='ALT.NET'/><category term='GC'/><category term='MSMQ'/><category term='serialization'/><category term='rebase'/><category term='WPF'/><category term='.NET'/><title type='text'>Kelly Leahy (technical)</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>42</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-576564674519310907</id><published>2011-08-24T19:58:00.000-07:00</published><updated>2011-08-24T20:48:20.756-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Azure Fast Deployment Web Deploy'/><title type='text'>Azure Fast-Deploy</title><content type='html'>&lt;div&gt;We have been building a web system on Windows Azure for quite a while now in my company, and are very familiar with the 20 minute development cycle of redeploying an Azure Role.  Recently, the Windows Azure team released a streamlining process for doing web deployments to Azure (for development purposes only, not production deployments).  Andy Cross talks about it here: &lt;a href="http://blog.bareweb.eu/2011/04/using-web-deploy-in-azure-sdk-1-4-1/"&gt;http://blog.bareweb.eu/2011/04/using-web-deploy-in-azure-sdk-1-4-1/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;The azure team blog talks about it &lt;a href="http://blogs.msdn.com/b/windowsazure/archive/2011/04/15/now-available-windows-azure-sdk-1-4-refresh-with-webdeploy-integration.aspx"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We tried to use Web Deploy, but we don't do things from Visual Studio.  We instead do everything from the command line for our automation (since we do a TON of automation).  As such, we tried for a while (to no avail) to get Web Deploy to work from the command line (tried for a while for us is measured in minutes not days, we don't have much patience for crappy tooling on our team).&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So...  we built our own.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It works like this - we have a very simple console app that we built in C# that looks at a particular blob storage account and tries to download a new blob from there if a new blob exists.  In our case, we've named the container "w-deploy-newbits" and the blob name is "WebRole.zip".  This zip file is built on our build machine by doing a msbuild /t:Publish on our ccproj in order to build a deployable version of our website (_PublishedWebsites\WebRole in our build folder).  We zip this file and upload it to the appropriate cloud location from the desktop as part of our build script (powershell with &lt;a href="https://github.com/JamesKovacs/psake"&gt;psake&lt;/a&gt;), and when the "NewBits" console app sees that new zip, it redeploys.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We have been using this technique for our profiling of our app (for performance) so that we can quickly make changes, redeploy, reprofile, and repeat the process.  It has worked VERY well for this.  We have no intention of using this for production releases or anything of that matter and would never recommend such a thing.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm going to try to make the code available in github, but it will probably take me some time to do so, as I need to remove anything sensitive to our own application setup and I'm really busy right now.  However, if you want more details about how we did this, please feel free to contact me via comments or my email address.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-576564674519310907?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/576564674519310907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=576564674519310907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/576564674519310907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/576564674519310907'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2011/08/azure-fast-deploy.html' title='Azure Fast-Deploy'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-8956185577129177578</id><published>2011-02-20T21:56:00.000-08:00</published><updated>2011-02-20T22:03:57.166-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='rebase'/><title type='text'>Setting up branches to always rebase in git</title><content type='html'>So, today at Harmony Hackathon, several people asked me to post the way to set up your branches in git to always rebase.  I know this is a controversial thing in git, if you disagree with me on why you might want to rebase, I don't care.  I like it and all I'm doing in this post is telling people how to do it if they want to.  Don't do it if you're afraid of rebase, you don't want rebase, or you are afraid your friends will shun you for using rebases by default.  Don't tell me if you don't like rebase, because I don't care ;)&lt;br /&gt;&lt;br /&gt;Ok... I'm going to tell you how to set up rebase to ALWAYS rebase on ALL repos.  If you don't want this for all repos, then you can do this on a per-repo basis by doing all the config without "--system".  Also, you can use "--global" instead of "--system" if you want to ensure that other people that use your machine aren't affected by the setting (nobody else uses my machines, so I don't care and do all my config at the --system level).&lt;br /&gt;&lt;br /&gt;So, to set up all "master" branches to do rebase by default - do the following:&lt;br /&gt;&lt;pre&gt;git config --system branch.master.rebase true&lt;/pre&gt;&lt;br /&gt;To set up all "new" remote tracking branches to be created with rebase by default, do:&lt;br /&gt;&lt;pre&gt;git config --system branch.autosetuprebase always&lt;/pre&gt;&lt;br /&gt;If you already have remote tracking branches, then I recommend you make sure you're current, delete the local branches, and recreate them (1.7.x does this automatically if you use the branch name to check out the remote branch, so make sure you're using Git 1.7.x or later for that hawtness (as darkxanthos would say)).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-8956185577129177578?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/8956185577129177578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=8956185577129177578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8956185577129177578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8956185577129177578'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2011/02/setting-up-branches-to-always-rebase-in.html' title='Setting up branches to always rebase in git'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-2638370215540236135</id><published>2011-02-20T21:21:00.000-08:00</published><updated>2011-02-20T21:55:47.028-08:00</updated><title type='text'>Resharper: Please indent my shit by 1000 miles, please!  kthxbye</title><content type='html'>So... Today, while at the Harmony Hackathon, I took a few minutes of yak shaving time to figure out the location of the setting that had all of us at the hackathon cursing resharper from time to time. If you want to see an example of why we were cursing, see a screenshot below from visual studio for one of the methods we were working on.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/59752516@N03/5463633427/" title="resharperlove by kelly.p.leahy, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5093/5463633427_111a019986_b.jpg" width="717" height="475" alt="resharperlove" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Resharper has a setting that tells it to indent the crap out of array and object initializers, and the default is "please resharper, indent my shit off the screen so far to the right that I run out of scrollbar space if I have more than two nested lambdas or objects". Today we took to rectifying this problem in our configuration.&lt;br /&gt;&lt;br /&gt;The setting is under formatting style / other / other / indent array, object and collection initializers. You can see it in the screenshot below. Uncheck it and stop bitching about resharper moving your shit 1000 miles to the right ;)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/59752516@N03/5463659909/" title="resharpersettings by kelly.p.leahy, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5180/5463659909_6318ee7665_b.jpg" width="700" height="700" alt="resharpersettings" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-2638370215540236135?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/2638370215540236135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=2638370215540236135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2638370215540236135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2638370215540236135'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2011/02/resharper-please-indent-my-shit-by-1000.html' title='Resharper: Please indent my shit by 1000 miles, please!  kthxbye'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5093/5463633427_111a019986_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-6951612196162164266</id><published>2010-03-18T02:14:00.001-07:00</published><updated>2010-03-18T02:24:45.995-07:00</updated><title type='text'>Not your mama’s sort algorithm</title><content type='html'>&lt;p&gt;So, not all that long ago, we were profiling our application, and I noticed that a particular part of our system was consuming a huge amount of time sorting arrays of 300,000 to 1M items.&amp;nbsp; I was a little surprised to see that this was taking an inordinate amount of time but it shouldn’t have been so surprising to me, since the keys by which we were sorting these arrays are somewhat complex and so comparisons are nontrivial.&lt;/p&gt; &lt;p&gt;The arrays we were sorting were lists of keys (and their associated data), and we were sorting them in a lexicographic ordering that was based on an elsewhere defined sort order (that was defined by the user).&amp;nbsp; The keys are themselves a list of id-value pairs where the ‘id’ is a short integer, and the value is a string.&amp;nbsp; So, as an example, consider the problem of sorting the following list in lexicographic order by the key ids 3, 4, 0 (in that order):&lt;/p&gt; &lt;ul&gt; &lt;li&gt;(0 = “UL1”, 3 = “M”, 4 = “S”)&lt;/li&gt; &lt;li&gt;(3 = “F”, 0 = “UL4”, 4 = “S”)&lt;/li&gt; &lt;li&gt;(4 = “S”, 3 = “M”, 0 = “UL2”)&lt;/li&gt; &lt;li&gt;(4 = “N”, 3 = “F”)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;When looking at the data, a few things stand out.&amp;nbsp; Firstly, the keys aren’t all in the same “internal order”.&amp;nbsp; This is because the keys come from various different places in the system and are created at various different times, and are not sorted because the cost of doing so proved to be a performance issue.&amp;nbsp; Secondly, not all of the keys have all of the key ids (0, 3, and 4).&amp;nbsp; This is a feature of our system where not all keys require all ids.&amp;nbsp; Keys cannot overlap, but a missing ‘id’ is a wildcard, and allows searches to match that key with any value for that id.&lt;/p&gt; &lt;p&gt;When doing a comparison between these keys, we were using a IComparer implementation that looks like the following code snippet.&amp;nbsp; The IKeyInstance interface is the interface for the objects that contain one of the rows of the above list of data.&amp;nbsp; GetValue returns the string associated with the id passed as its argument (or null if the value doesn’t exist in the key).&lt;/p&gt; &lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt; &lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; KeyInstanceSortedComparer : IComparer&amp;lt;IKeyInstance&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;short&lt;/span&gt;[] _KeyIdSortOrder;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; KeyInstanceSortedComparer(IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;short&lt;/span&gt;&amp;gt; keyIdSortOrder)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         _KeyIdSortOrder = keyIdSortOrder.ToArray();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Compare(IKeyInstance keyInstanceA, IKeyInstance keyInstanceB)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var keyId &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _KeyIdSortOrder)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;             var keyValueA = keyInstanceA.GetValue(keyId);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;             var keyValueB = keyInstanceB.GetValue(keyId);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;             var compareResult = &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Compare(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;                 keyValueA.ToValue(), &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;                 keyValueB.ToValue());&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (compareResult != 0)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; compareResult;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The _KeyIdSortOrder field is the sort order for the particular sort operation we are performing when using this comparer.&amp;nbsp; The ToValue method is an extension method that returns the value’s string if it’s non-null, or null otherwise.&amp;nbsp; It’s pretty easy to see from this snippet that this code implements a lexicographic sort on the IKeyInstance implementers.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, given the fact that the IKeyInstance implementers did not sort their id-value pairs internally, GetValue has to do a linear search of the key instance in order to find the appropriate value.&amp;nbsp; Additionally, the comparator must compare as many keyId’s values as it encounters until it either reaches the end of the list of id’s to compare, or it finds an id for which the two keys have different values.&amp;nbsp; The keys are never larger than about 25 ids in any key, and they are typically more like 2 – 8 id-value pairs per key.&amp;nbsp; Also, much of the memory consumed in the runtime footprint of our application was at one point held by these IKeyInstance implementers or their associated id-value pairs, so every effort to keep their size down must be made.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;One of the optimizations we made to reduce the size of these key instances was to manufacture the strings used as “values” for the id-value pairs from a factory that coalesced duplicates so that we only ever had one instance of a given value in memory at any point in time.&amp;nbsp; Another optimization was to do the same with id-value pairs themselves.&amp;nbsp; These two combined optimizations had a profound impact on the memory footprint of our application, due to the amount of duplication present in the data, and the limited amount of uniqueness in the key’s values and id-value pairs.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Anyway, to get back to the sorting, I spent some time looking at the sort performance and realized that no matter what I did, I couldn’t really improve the performance of the sort much, so long as we were continuing to do all these comparisons.&amp;nbsp; The problem is, the comparisons are simply expensive due to the nature of GetValue in IKeyInstance and the fact that we weren’t sorting the entries.&amp;nbsp; We could have used Dictionary in the key instances, but that would have taken up too much memory for our taste.&amp;nbsp; We could have used a sorted list of id/value pairs, but when there are only typically 2-8 columns in the key, binary search would likely only be slightly faster than a linear search, and may have even been slower.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So….&amp;nbsp;&amp;nbsp; I started looking for ways to parallelize the algorithm.&amp;nbsp; One of the other developers on my team – Robert Ream – was looking into parallel implementations of quicksort and mergesort to try to figure out how we could improve the performance of our sorting, since we have a few processors at our disposal on our typical users’ machines.&amp;nbsp; I also asked him to look into ways of making the algorithm cancellable and restartable so that we could ‘stop’ the algorithm in progress, serialize its state to disk, and move on to another item in the UI without losing the work that had already been done.&amp;nbsp; While this was a very interesting problem to solve, it turned out that trying to get rid of the comparisons would bear much more tasty fruit.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Thinking outside the box&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;In the process of looking for ways to reduce the number of comparisons, I started talking to Robert about which of the algorithms we knew about had less comparisons (mergesort / quicksort / etc.).&amp;nbsp; After some discussion, we really didn’t end up anywhere useful, so Robert continued working on his parallel quicksort implementation.&amp;nbsp; In the meantime, the weekend came, and I decided to spend a couple hours researching what else could be done.&amp;nbsp; I pulled out Knuth’s TAOCP Vol 3 and started reading.&amp;nbsp; In it, I came across his description of radix sort.&amp;nbsp; I read his description, which didn’t lead me to any great revelations (since he basically said that it doesn’t typically perform that much better than the other algorithms), but I was intrigued by the fact that it didn’t use comparisons.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I then continued searching for information, reading Cormen, and a couple of other algorithm books I have around the house, and then did some searching online.&amp;nbsp; I came across several publications by Stefan Nilsson on the subject of radix sort, and read some of them.&amp;nbsp; It turns out that after reading a few of these I started to think about our problem a bit more and try to consider whether it could be framed in a structure that allowed us to apply radix sort.&amp;nbsp; Still, the complete lack of comparisons was the motivating factor for me, given my knowledge of the fact that the comparisons were more than 95% of the time spent in our sorting code.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After a few hours of thought on the subject on Friday, I decided Saturday afternoon to investigate a bit in code.&amp;nbsp; So, if you don’t have any background on radix sort, the basic idea is this – instead of using comparisons, you must have numerical values that can be assigned to the ‘values’ of your key elements being sorted, and the assignment must be in the same order as your sort order.&amp;nbsp; For instance, if you want to sort a bunch of strings, the values are the ASCII values of the characters (or at least their ASCII sort collation order number).&amp;nbsp; Radix sort takes advantage of this fixed space to allow you to do array assignments and simple linked list operations instead of doing comparisons.&amp;nbsp; Radix sort performs best if you have a large ‘alphabet’ of values to work with and your keys are either non-overlapping, or don’t have a very large number of duplicates.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There are several variations of radix sort algorithms - the two classifications are MSD and LSD approaches.&amp;nbsp; I used the MSD approach since it was easier to understand how it applied to my problem, and I originally thought I had varying length keys so it seemed like it would be more appropriate (LSD approach seems to work better with fixed-length keys).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In order to apply radix sort to my problem, I needed to be able to assign a value to each key-value in my key.&amp;nbsp; Since I already had a factory that maintained the invariant that there was only one instance of each key-value in memory at any given point in time, and in order to do this, the factory needed to track these objects, I decided to provide the ability for the factory to assign a ‘sort order’ value to each of the key-values.&amp;nbsp; An integer was big enough, and I could put some intelligence in the caching factory to have it only perform the sort when requested AND necessary (due to a change having occurred to the list of key-values).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Given these sort order values, I could define an “alphabet” of 0..N where N is the number of values in existence and the highest sort order value, 1 is the lowest, and 0 represents a missing id in the key.&amp;nbsp; Then, I could logically think of my keys as looking like ordered M-tuples of integers (where M is the number of IDs in my sort order specification, and the maximum number of id-value pairs to be found in any key).&amp;nbsp; The integers in these M-tuples were the sort order values from the key-value list, and the tuples were logically sorted in the appropriate order for doing the lexicographic sort.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Then, the keys above could (fictitiously) look something like (in the sort order 3, 4, 0):&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;(2, 4, 5)&amp;nbsp;&amp;nbsp; //(0 = “UL1”, 3 = “M”, 4 = “S”)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(1, 4, 7)&amp;nbsp;&amp;nbsp; //(3 = “F”, 0 = “UL4”, 4 = “S”)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(2, 4, 6)&amp;nbsp;&amp;nbsp; //(4 = “S”, 3 = “M”, 0 = “UL2”)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(1, 3, 0)&amp;nbsp;&amp;nbsp; //(4 = “N”, 3 = “F”)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;with the sort order values being:&lt;/p&gt;&lt;br /&gt;&lt;p&gt; (1 = F, 2 = M, 3 = N, 4 = S, 5 = UL1, 6 = UL2, 7 = UL4)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;and the prescribed sort order is, of course&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;(1, 3, 0)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(1, 4, 7)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(2, 4, 5)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(2, 4, 6)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Implementation of Radix Sort&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;So, armed with this approach of assigning ordinal positions to the values in my keys, and the logical definition of a key as given above, I was in a position to apply radix sort (which requires a desired lexicographic ordering and known ‘cardinal’ values for the letters of the alphabet you are sorting).&amp;nbsp; My implementation breaks into three pieces – an ‘inner’ algorithm (in my case bucketsort), a sorter, and a way to track the unfinished portions of the array being sorted.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The basic idea of my implementation is that you start with the full array as a single ‘unsorted’ range.&amp;nbsp; The algorithm loops as long as there is work to do, by removing a single unsorted range from a queue, processing that unsorted range, and then moving on to the next step.&amp;nbsp; Once there is no more work to do, the array is sorted.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The algorithm requires an ‘inner’ sort algorithm, since radix sort processes one ‘digit’ at a time from the source alphabet.&amp;nbsp; In my case, radix sort will process one key-value column at a time, starting from left to right.&amp;nbsp; When processing a column, it will use a working array that has one linked list for each possible value of the digit.&amp;nbsp; For instance, we would have a working array (of linked lists) of length 8 (since there are 7 distinct key values, plus one ‘missing’ key value).&amp;nbsp; The sort will walk linearly through the list putting items into the ‘bucket’ that corresponds to the value for the first column.&amp;nbsp; Then, after it has assigned all items to their appropriate buckets, it will put those items back into the array in the order in which they appear in the array and their linked list.&amp;nbsp; At this point, the array is sorted by the first column, and the work remaining to be processed is the list of buckets of length 2 or more.&amp;nbsp; The process is iteratively applied to each column, ignoring the values of previous columns, but when applying for a column, it is only applied to the subset being currently processed (i.e. after splitting buckets 1 and 2, the ‘remaining work’ will be the ranges (0, 2) and (2, 2), where the tuples are (start, length).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The work of splitting items into their buckets is mostly done by my ‘RadixSortBucketer’ class, given here:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RadixSortBucketer&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; LinkedList&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt;[] _Buckets;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RadixSortBucketer(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; bucketCount)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         _Buckets = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LinkedList&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt;[bucketCount];&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; AddItem(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; bucket, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; item)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         var list = _Buckets[bucket];&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(list == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;             _Buckets[bucket] = list = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LinkedList&amp;lt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         list.AddLast(item);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SaveItemsTo(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;         LinkedList&amp;lt;RadixSortUnfinishedRange&amp;gt; unsortedRanges, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;[] workArray, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; startOffset)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         var targetIndex = startOffset;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var list &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _Buckets.Where(b =&amp;gt; b != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(list.Count &amp;gt; 1)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;                 unsortedRanges.AddLast(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;                     &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RadixSortUnfinishedRange(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;                         targetIndex, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;                         list.Count));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; list)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;                 workArray[targetIndex++] = item;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Clear()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(var i = 0; i &amp;lt; _Buckets.Length; i++)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;             _Buckets[i] = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The array of LinkedList&amp;lt;int&amp;gt; is the buckets, the LinkedList&amp;lt;int&amp;gt; in each bucket is (possibly empty) list of indices that fall into that bucket.&amp;nbsp; The unsorted range object looks like:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RadixSortUnfinishedRange&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Start;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Count;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RadixSortUnfinishedRange(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; start, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; count)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;         Start = start;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;         Count = count;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;and the overall algorithm looks like:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RadixSorter&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; ValueFunctionDelegate(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; level, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; item);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; RadixSortBucketer _Bucketer;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt;[] _WorkArray;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ValueFunctionDelegate _ValueFunction;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _LevelCount;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RadixSorter(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;[] arrayToSort, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; bucketCount, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; levelCount, ValueFunctionDelegate valueFunction)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;         _WorkArray = arrayToSort;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         _Bucketer = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RadixSortBucketer(bucketCount);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         _LevelCount = levelCount;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;         _ValueFunction = valueFunction;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Sort()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;         var currentLevel = 0;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;         var currentUnsortedRanges = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LinkedList&amp;lt;RadixSortUnfinishedRange&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         currentUnsortedRanges.AddLast(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RadixSortUnfinishedRange(0, _WorkArray.Length));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;while&lt;/span&gt;(currentUnsortedRanges.Count &amp;gt; 0)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;             var nextUnsortedRanges = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LinkedList&amp;lt;RadixSortUnfinishedRange&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var range &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; currentUnsortedRanges)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;             {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;                 _Bucketer.Clear();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = range.Start, j = 0; j &amp;lt; range.Count; i++,j++)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;                     _Bucketer.AddItem(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;                         _ValueFunction(currentLevel, _WorkArray[i]),&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;                         _WorkArray[i]);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;                 _Bucketer.SaveItemsTo(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;                     nextUnsortedRanges,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;                     _WorkArray,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;                     range.Start);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt;             }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  42:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  43:&lt;/span&gt;             currentUnsortedRanges = nextUnsortedRanges;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  44:&lt;/span&gt;             currentLevel++;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  45:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(currentLevel &amp;gt;= _LevelCount)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  46:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  47:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  48:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  49:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The only ‘special’ part of this is that I have defined a delegate to allow this to be parameterized.&amp;nbsp; The delegate is a value function that returns the integral value corresponding to a particular item and ‘level’ (level is like the ‘current column’ value).&amp;nbsp; In my particular problem, the value function is a delegate that uses the ‘level’ to determine which ‘value’ to ask for, and returns 0 if there is no value, or the sort order of the value if the value is not null.&amp;nbsp; Item is the index into the original array to use when getting values for the algorithm.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Conclusion?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;So, what was the end result of my experimentation, you ask?&amp;nbsp; Well, the sort that used to take 17 seconds or so, now takes under 1 second, and much less if it doesn’t include the cost of assigning the sort orders to the key values (which doesn’t happen for each sort, it only happens for the first sort after a change to the key-value cache – which is pretty infrequent).&amp;nbsp; Could my implementation be more efficient – absolutely.&amp;nbsp; However, I’m a strong believer in “write it the way that makes the most sense to you, and then only make it ‘more efficient’ if profiling shows it to need to be more efficient” – this is basically the philosophy of avoiding ‘premature optimization’.&amp;nbsp; Of course, I don’t condone ‘premature pessimisation’ either, so you shouldn’t choose the wrong algorithm or data structure for the job, but you also shouldn’t micro-optimize every bit of code you write, as you’re writing it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I hope you find this description useful – I tried to give details about how &amp;amp; why I did what I did, instead of just ‘what’ I did.&amp;nbsp; Hopefully that makes this an interesting read and provides some insights that just posting the code wouldn’t provide.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-6951612196162164266?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/6951612196162164266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=6951612196162164266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6951612196162164266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6951612196162164266'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2010/03/not-your-mamas-sort-algorithm.html' title='Not your mama’s sort algorithm'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4875412093951124558</id><published>2010-03-16T22:14:00.001-07:00</published><updated>2010-03-16T22:36:57.757-07:00</updated><title type='text'>Weak Events</title><content type='html'>&lt;p&gt;A while back I was having a discussion with my friend Tim Erickson (@imerickson) about problems surrounding GC and events in WPF.&amp;nbsp; Specifically, we were talking about problems with ICommand (WPF) implementations.&amp;nbsp; I mentioned to him that we have and use our own weak eventing pattern on my team.&amp;nbsp; I promised to write a blog post about it, but I’ve been slow doing so.&amp;nbsp; This is my attempt to make good on my promise.&amp;nbsp; Hopefully it’s not too awful.&lt;/p&gt; &lt;p&gt;The problem that weak events are meant to solve is one in which you an event source (the thing raising the events) that has a potentially longer lifetime than some of the corresponding event sinks (the things receiving the events).&amp;nbsp; In that case, normal .NET events (delegates) will cause the event source to keep the event sinks alive, unless some explicit event removal code is executed on the sinks to tell them to remove their event handlers from the source.&amp;nbsp; In many cases this is relatively easy to do, but in many it is very inconvenient to do so and the programmer would rather not “know” when the removal is necessary.&lt;/p&gt; &lt;p&gt;As an example, in our application, we have an editor grid that has bindings that act as an event source, while the grid acts as an event sink.&amp;nbsp; BTW, when I say “bindings” here, think of them as a ‘data source’ for the grid, not ‘bindings’ in the WPF sense.&amp;nbsp; These bindings are not really a problem, as the bindings are created and “attached” to the grid, and when they are “detached” from the grid, the grid removes any event handlers it has attached to the bindings.&amp;nbsp; In this case, we don’t need weak events.&amp;nbsp; However, underlying the grid bindings is a view model object (that is sort of an amalgamation of a view model and a data model object, but that’s an argument for another day) that has events to notify its subscribers if any of the contents of the VM have changed from anywhere in the UI.&lt;/p&gt; &lt;p&gt;In our UI, we can have multiple views on the same exact model object (think multiple views in MS Excel or MS Word) that each need to be notified if any one of the views causes a change in the model.&amp;nbsp; In this case, our model is an event source, and our bindings are an event sink.&amp;nbsp; Here’s the problem – our model lives “forever” (at least it lives as long as our application is ‘running’), yet the grid bindings get recreated when the user changes their view, moves to another item, opens a new view, or any number of other changes to the state of the UI.&amp;nbsp; In effect, we create MANY of these grid bindings objects throughout a single run of our application, and we wish to make no effort to track when they are no longer “in use”, since doing so is rather difficult and would litter our code everywhere with code to handle this tracking.&lt;/p&gt; &lt;p&gt;However, if we ignore the tracking, and just let the grid bindings “get released” by the grid, etc., the events that were hooked by the bindings from the model in order to get notifications of changes in the model will never get unhooked.&amp;nbsp; This will lead to the model “keeping alive” a huge number of these bindings objects and never releasing them, effectively creating a “memory leak” until the model is shut down.&amp;nbsp; Therefore, we had a choice – either hook the events and try to force appropriate shutdown in all the places it was needed, or find another solution that didn’t involve the bindings hooking events directly on the model.&lt;/p&gt; &lt;p&gt;Since we have total control over both the control and the underlying model, we had a lot of flexibility in our choice of solutions to this dilemma.&amp;nbsp; I investigated the .NET (WPF) model for weak events, as well as several other methods people had used on the net.&amp;nbsp; I even found a description from the venerable Jeffrey Richter in his CLR via C# book (and found it to have errors, as a matter of fact).&amp;nbsp; The WPF model is very general and is the way to go if you are building a control and don’t have control over the model that will be hooked to your control (or want to play nice in the WPF data binding way), but it leaves much to be desired in terms of the programming model.&lt;/p&gt; &lt;p&gt;The WPF weak event model is centered around the Microsoft.Windows.IWeakEventListener interface and the Microsoft.Windows.WeakEventManager base class.&amp;nbsp; For a discussion of some of the details, see &lt;a title="http://blogs.msdn.com/nathannesbit/archive/2009/05/28/weakeventmanager-and-iweakeventlistener.aspx" href="http://blogs.msdn.com/nathannesbit/archive/2009/05/28/weakeventmanager-and-iweakeventlistener.aspx"&gt;http://blogs.msdn.com/nathannesbit/archive/2009/05/28/weakeventmanager-and-iweakeventlistener.aspx&lt;/a&gt;&lt;/p&gt; &lt;p&gt;For the most part, I agree with Nathan’s assessment of this class.&amp;nbsp; I do, however, believe that if you are writing controls to be consumed by applications out of your control, you effectively MUST follow this model (not mine or anyone else’s), since this is the model that is used throughout WPF.&amp;nbsp; While you could implement your own variation of this model, you still need to apply the general concepts that it does in any solution you come up with (i.e. the ‘endpoint’ providing the ‘weakness’ in the events is the event sink, not the event source).&lt;/p&gt; &lt;p&gt;For our application, we have adopted the ‘opposite’ pattern – that is, that the weak events should be sourced from the event source as weak, rather than having an intermediary in the weak event manager that handles turning ‘strong’ events from the model into ‘weak’ events (listeners) on the event sink.&amp;nbsp; We like this model because it hides the complexity of dealing with the ‘weakness’ of the events behind the facade of the event handler attachment points and ‘invocations’ in the model.&amp;nbsp; Our model basically works as follows: the event source provides a custom event implementation, and when sinks subscribe to this event, they are added to a weak event “multicast delegate-like” object that is private to the event source.&amp;nbsp; The subscribers don’t know that they are hooking to a weak event.&amp;nbsp; On the other hand, the model raises events using this “special weak event object” and the attached event sinks receive these messages if they are still alive.&lt;/p&gt; &lt;p&gt;There is one small wrinkle to our model.&amp;nbsp; Event handlers attached to weak events in this manner MUST be kept around by something else, or else they will get collected and will cease to receive events.&amp;nbsp; This isn’t a problem for us, since it’s exactly what we’d like to see happen, but there can be problems if one isn’t careful, as it will seem like events stop getting ‘caught’ by their intended targets, and you won’t know why.&lt;/p&gt; &lt;p&gt;So, now on to the details.&amp;nbsp; First off, we have a ‘WeakDelegate’ class, that is responsible for being a weak version of the Delegate class built in to the .NET framework.&amp;nbsp; It looks like the following:&lt;/p&gt; &lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt; &lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// A "weak reference" version of a delegate.  This class is used &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// by the MulticastWeakDelegate type to support "weak events" &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// pattern in the system.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;typeparam name="T"&amp;gt;The type of delegate to return.&amp;lt;/typeparam&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; WeakDelegate&amp;lt;T&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; WeakReference _Target;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; MethodInfo _Method;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Constructs a weak delegate from the provided delegate.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="source"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; WeakDelegate(Delegate source)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (source == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color: #006080"&gt;"source"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (source.Target == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"Source points to a null target.  "&lt;/span&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;                 + &lt;span style="color: #006080"&gt;"This is not usable as a weak reference."&lt;/span&gt;, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"source"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (source.GetType() != &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"Source is not the proper delegate type.  "&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;                 + &lt;span style="color: #006080"&gt;"The delegate type must match the type passed "&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;                 + &lt;span style="color: #006080"&gt;"as the type parameter 'T'"&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"source"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;         _Target = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WeakReference(source.Target);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;         _Method = source.Method;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Returns the contents of the WeakDelegate as a proper &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Delegate object, or NULL if the&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// delegate's target has been collected already.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  42:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; T Delegate&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  43:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  44:&lt;/span&gt;         get&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  45:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  46:&lt;/span&gt;             var obj = _Target.Target;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  47:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (obj == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  48:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  49:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (T)(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;)System.Delegate.CreateDelegate(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  50:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T), _Target.Target, _Method);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  51:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  52:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  53:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  54:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  55:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// This property identifies if the delegate target has &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  56:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// already been collected (false if so).  Note: there is a &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  57:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// possible race condition with this property, so be sure to &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  58:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// check the return value of the Delegate property for null &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  59:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// even if IsAlive returned true.  This is just a quick way to &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  60:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// identify as "definitely dead", it cannot be trusted not to &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  61:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// change between calling it and calling the Delegate method!&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  62:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  63:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsAlive&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  64:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  65:&lt;/span&gt;         get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _Target.IsAlive; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  66:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  67:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  68:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  69:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Checks whether the contents of this weak delegate is the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  70:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// same as the delegate passed as a parameter.  If it &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  71:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// contains the same target &amp;amp; method combination, then the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  72:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// function returns true.  If the contained "delegate" has &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  73:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// already been collected, or doesn't match the passed &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  74:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// delegate, it returns false.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  75:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  76:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="other"&amp;gt;The delegate to test against.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  77:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;returns&amp;gt;True if the delegate is the same as the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  78:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// target/method contained by this weak delegate, False if &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  79:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// the weak delegate has already been collected or if the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  80:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// target/method differs.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  81:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsSameAs(Delegate other)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  82:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  83:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; ReferenceEquals(other.Target, _Target.Target)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  84:&lt;/span&gt;                &amp;amp;&amp;amp; other.Method.Equals(_Method);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  85:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  86:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The weak delegate has support for “wrapping” a normal .NET delegate (it, of course, copies the contents of the delegate and throws away the underlying delegate so that it can hold a weak reference to the target of the original delegate).&amp;nbsp; It also has support for asking about the validity of the weak reference, getting the delegate back (or null if it’s not alive anymore), and comparing this delegate to others (used in the ‘remove’ handler of events).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To implement weak events, we use these weak delegates in a similar way to the MulticastDelegate class’ use in C# (the class that is used for ‘event’ implementation).&amp;nbsp; For this, we have a MulticastWeakEvent generic class that allows us to get as close as possible to declaring an ‘event’ in C#, but the language won’t let us get quite there.&amp;nbsp; Here is our MulticastWeakEvent implementation:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// MulticastWeakEvent is the "weak event" pattern support object.  This class &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// allows classes that wish to provide weak event registration to do so.  One &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// of these delegate classes must be created for each event, and the class &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// must be given the event type (typically EventHandler&amp;amp;lt;TEventArgs&amp;amp;gt;) and &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// the type of the event arguments.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;typeparam name="TEventType"&amp;gt;The type of event to support.  This should &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// normally be the .NET 2.0 EventHandler&amp;amp;lt;TEventArgs&amp;amp;gt; type.&amp;lt;/typeparam&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;typeparam name="TEventArgs"&amp;gt;The type of the event arguments object to use &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// in calls to this event.&amp;lt;/typeparam&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MulticastWeakEvent&amp;lt;TEventType, TEventArgs&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; TEventType : &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; TEventArgs : EventArgs&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;WeakDelegate&amp;lt;TEventType&amp;gt;&amp;gt; _List;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; Action&amp;lt;TEventType, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;, TEventArgs&amp;gt; _InvokeAction;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Delegate _AsDelegate(TEventType handler)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (Delegate)(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;)handler;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Constructs a new weak event delegate.  The action should simply call &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// the delegate with the appropriate arguments.  For instance, the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// action should simply be a delegate that looks like &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;code&amp;gt;(d,s,e) =&amp;amp;gt; d(s,e)&amp;lt;/code&amp;gt;.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="invokeAction"&amp;gt;A delegate that invokes its first argument &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// (the event delegate) passing the second and third arguments as the &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// arguments to the invocation.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; MulticastWeakEvent(Action&amp;lt;TEventType, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;, TEventArgs&amp;gt; invokeAction)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Delegate).IsAssignableFrom(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(TEventType)))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; InvalidOperationException(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"TEventType must be a delegate type in MulticastWeakDelegate"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;         _List = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;WeakDelegate&amp;lt;TEventType&amp;gt;&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;         _InvokeAction = invokeAction;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  42:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  43:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  44:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Invokes the event for all listeners, one at a time.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  45:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  46:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="sender"&amp;gt;The sender to pass to the invocation.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  47:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="e"&amp;gt;The event args for the invocation.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  48:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Invoke(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, TEventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  49:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  50:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;lock&lt;/span&gt; (_List)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  51:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  52:&lt;/span&gt;             _List.RemoveAll(eh =&amp;gt; !eh.IsAlive);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  53:&lt;/span&gt;             _List.ForEach(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  54:&lt;/span&gt;                 eh =&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  55:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  56:&lt;/span&gt;                     var target = eh.Delegate;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  57:&lt;/span&gt;                     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (target != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  58:&lt;/span&gt;                         _InvokeAction(target, sender, e);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  59:&lt;/span&gt;                 });&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  60:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  61:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  62:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  63:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  64:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Adds a handler to the weak event invocation list.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  65:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  66:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="handler"&amp;gt;The handler delegate.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  67:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; AddHandler(TEventType handler)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  68:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  69:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;lock&lt;/span&gt; (_List)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  70:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  71:&lt;/span&gt;             _List.RemoveAll(eh =&amp;gt; !eh.IsAlive);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  72:&lt;/span&gt;             _List.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WeakDelegate&amp;lt;TEventType&amp;gt;(_AsDelegate(handler)));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  73:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  74:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  75:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  76:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  77:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Removes a handler from the weak event invocation list (and compacts &lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  78:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// the list).&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  79:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  80:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="handler"&amp;gt;The handler delegate.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  81:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RemoveHandler(TEventType handler)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  82:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  83:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;lock&lt;/span&gt; (_List)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  84:&lt;/span&gt;             _List.RemoveAll(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  85:&lt;/span&gt;                 eh =&amp;gt; (!eh.IsAlive) || eh.IsSameAs(_AsDelegate(handler)));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  86:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  87:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  88:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  89:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MulticastWeakEvent : MulticastWeakEvent&amp;lt;EventHandler, EventArgs&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  90:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  91:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; MulticastWeakEvent(): &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;((d, s, e) =&amp;gt; d(s, e))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  92:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  93:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  94:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, given this class, we can show some examples on how to expose weak events.&amp;nbsp; Consider a class that has a “NameChanged” event of type EventHandler&amp;lt;NameChangeEventArgs&amp;gt;.&amp;nbsp; We can declare a subclass of MulticastWeakEvent (not strictly necessary, but helps with readability) as:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; NameChangeEventArgs: EventArgs&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; OldName;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; NewName;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; NameChangeEventArgs(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; oldName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; newName)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;         OldName = oldName;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;         NewName = newName;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; NameChangedEvent: &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;     MulticastWeakEvent&amp;lt;EventHandler&amp;lt;NameChangeEventArgs&amp;gt;, NameChangeEventArgs&amp;gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; NameChangedEvent()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;         : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;((d, s, e) =&amp;gt; d(s, e))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The main reason for declaring a special type for one of these events is that it helps avoid the silly (d,s,e) =&amp;gt; d(s, e) crap that we’re forced to do so that we can avoid reflection costs in our code.&amp;nbsp; I couldn’t find a way around this without using reflection, so if someone has any ideas I’d be happy to hear about them (but don’t be surprised if I’m skeptical, since I fought this problem for a very long time).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, to create a model object that raises events of the type NameChanged (transparently), we can do the following:&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IPerson&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { get; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; EventHandler&amp;lt;NameChangeEventArgs&amp;gt; NameChanged;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Person: IPerson&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _Name;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; NameChangedEvent _NameChanged = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NameChangedEvent();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Person(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; nameAtBirth)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         _Name = nameAtBirth;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;         get&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _Name;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         set&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(_Name == &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;             var oldName = _Name;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;             _Name = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;             _NameChanged.Invoke(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NameChangeEventArgs(oldName, _Name));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; EventHandler&amp;lt;NameChangeEventArgs&amp;gt; NameChanged&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;         add { _NameChanged.AddHandler(&lt;span style="color: #0000ff"&gt;value&lt;/span&gt;); }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;         remove { _NameChanged.RemoveHandler(&lt;span style="color: #0000ff"&gt;value&lt;/span&gt;); }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;I think this programming model is pretty clean, and it works well for what we’re doing.&amp;nbsp; The only caveat, as I said earlier, is that you absolutely must understand how GC works when working with these, or else you’ll have some very weird bugs related to event sinks disappearing in the night ;)&amp;nbsp; Allow me to give an example of the “event sink disappearing” problem in case you haven’t figured out what I’m referring to yet.&amp;nbsp; Consider the following code:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PersonWatcher&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;IPerson&amp;gt; _PeopleWithNameChanges = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;IPerson&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;IPerson&amp;gt; GetPeopleWithNameChanges()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _PeopleWithNameChanges;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Listener&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;IPerson&amp;gt; _TargetList;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Listener(List&amp;lt;IPerson&amp;gt; targetList)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;             _TargetList = targetList;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HandleNameChanged(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, NameChangeEventArgs args)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;             _TargetList.Add((IPerson)sender);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ListenToPerson(Person personToListenTo)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;         var listener = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Listener(_PeopleWithNameChanges);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;         personToListenTo.NameChanged += listener.HandleNameChanged;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The code above (while only an example) could, or at least some variation of it could very well arise in ‘real life’.&amp;nbsp; One might think they are decoupling the ‘listening’ aspect from the tracking aspect of the problem.&amp;nbsp; The problem with this is that since the Person sources ‘weak’ events, there are no objects that are ‘live’ that are holding strong references to the ‘listener’ instances created on line 27 of the snippet.&amp;nbsp; This means that as soon as the GC decides to do so, the listener will get collected, and you won’t receive the events you expected to receive.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;One way around this is for something ‘live’ to hold on to the listeners until their work is done.&amp;nbsp; For instance, if the “PersonWatcher” class held on to a list of all its listeners, this would keep them alive.&amp;nbsp; Of course, this has the other problem of requiring you to release them at some point in order to allow them to get GCed, but that may not be such a big deal, considering you might know better when to do that release than you know when to ‘detach’ the event listeners.&amp;nbsp; In this particular example, I suspect it’s a wash.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Anyway, I hope you enjoyed this brief tour of our island of code surrounding weak references.&amp;nbsp; It has served us well thus far, even with the caveats I keep mentioning.&amp;nbsp; Until next time – happy coding!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4875412093951124558?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4875412093951124558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4875412093951124558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4875412093951124558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4875412093951124558'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2010/03/weak-events.html' title='Weak Events'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7844615891711793760</id><published>2009-12-18T18:36:00.000-08:00</published><updated>2009-12-18T18:38:13.764-08:00</updated><title type='text'>Creating a remote branch in Git</title><content type='html'>I just had to do this today, and I can't believe how unintuitive it is... At least I found this &lt;a href="http://www.zorched.net/2008/04/14/start-a-new-branch-on-your-remote-git-repository/"&gt;post&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7844615891711793760?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7844615891711793760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7844615891711793760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7844615891711793760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7844615891711793760'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2009/12/creating-remote-branch-in-git.html' title='Creating a remote branch in Git'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1469597862119172742</id><published>2009-02-22T15:59:00.000-08:00</published><updated>2009-02-22T16:01:48.739-08:00</updated><title type='text'>Binding to SelectedItems in WPF ListBox.</title><content type='html'>Here's a very interesting approach to solving the "can't bind to selected items" issue with the WPF ListBox control.  I'll definitely want to look into this more later, as I haven't had a chance to yet.  I'm still fighting issues getting CheckedItems initialized on my CheckListBox control that I've written and it suffers from the same issue as SelectedItems in ListBox.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Alex's blog has the approach I'm referring to.  &lt;a href="http://alexshed.spaces.live.com/blog/cns!71C72270309CE838!133.entry"&gt;Check it out.&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1469597862119172742?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1469597862119172742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1469597862119172742' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1469597862119172742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1469597862119172742'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2009/02/binding-to-selecteditems-in-wpf-listbox.html' title='Binding to SelectedItems in WPF ListBox.'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-6914594293542911961</id><published>2009-02-21T23:11:00.001-08:00</published><updated>2009-02-21T23:19:09.472-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HyperV perf issues'/><title type='text'>Holy Crap!  HyperV versus nVidia drivers - everyone loses!</title><content type='html'>&lt;p&gt;Wow, I've been trying to figure out why WPF apps are soooo slow on my machine for months now.  I just chalked it up to Server 2008 being a server OS and having all the goodies for fast rendering turned off, or something like that.&lt;/p&gt;&lt;p&gt;Today, I stumbled across a post on a forum about problems with HyperV causing video and other apps that "use" video to be really slow on startup and run very sluggish, causing problems with audio and other side effects.  It turns out that many (most) video drivers do not play well with HyperV (or HyperV doesn't play well with most video drivers - I'll let MS &amp;amp; the vendors argue over which is the correct statement, I'm staying out of the middle).  As such, when running HyperV, the machine can be very sluggish when apps do anything that accesses the video hardware (obviously something that VS2008, VLC media player, and WPF applications do a lot of).&lt;/p&gt;&lt;p&gt;Finally, I bit the bullet and decided to uninstall HyperV and after doing so, my apps immediately run way faster.  I'm not sure exactly how much faster, but I know that when running my UITestHarness app (part of the project I work on), the app would start up rather quickly, but when clicking on a button that shows a WPF window (the app is WinForms mainly), it would take a good 15 seconds to show the window.  Now, those windows show immediately (less than 1 second).  I find this rather amazing that there are such perf differences between HyperV and non HyperV configs.  Oh well, hopefully they'll fix them soon, or I'll find a video card that doesn't have problems (reportedly ATI cards are often in better shape), 'cause I really like HyperV!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-6914594293542911961?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/6914594293542911961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=6914594293542911961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6914594293542911961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6914594293542911961'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2009/02/holy-crap-hyperv-versus-nvidia-drivers.html' title='Holy Crap!  HyperV versus nVidia drivers - everyone loses!'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-5780639808044364611</id><published>2009-01-30T21:16:00.001-08:00</published><updated>2009-01-30T21:56:21.573-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GC'/><category scheme='http://www.blogger.com/atom/ns#' term='IDisposable'/><title type='text'>IDisposable and Garbage Collection</title><content type='html'>&lt;p&gt;I've had several discussions recently with friends and associates about garbage collection, IDisposable, and the disposal pattern recommended by Microsoft.&amp;#160; These discussions have brought to light many misconceptions, a few incorrect statements, and some good and bad advice.&amp;#160; In particular, the 'final straw' that led me to write this blog post is the &lt;a href="http://www.codinghorror.com/blog/archives/001211.html" target="_blank"&gt;post&lt;/a&gt; by Jeff Atwood (@CodingHorror) on his blog, and the &lt;a href="http://agilology.blogspot.com/2009/01/why-dispose-is-necessary-and-other.html" target="_blank"&gt;response&lt;/a&gt; by Jeff Tucker on his blog (Agilology).&lt;/p&gt;&lt;p&gt;I tend to lean more towards agreeing with Jeff Atwood (@CodingHorror)'s post, in that I believe that calling Dispose is absolutely an optimization.&amp;#160; That said, it's an optimization that in some cases simply should not be optional for all but those people who understand the precise implications of not doing so.&amp;#160; For instance, SqlConnection.&amp;#160; It's absolutely best practice to dispose of SqlConnection as soon as you can do so in applications that might use connection pooling.&amp;#160; On the other hand, there are resources such as FileStream, DataSet, and the many WaitHandle-derived types that you &lt;em&gt;may&lt;/em&gt; want to dispose of early, but it's absolutely an optimization (either in terms of memory footprint or resource contention) to do so early, not a requirement.&lt;/p&gt;&lt;p&gt;Among the things that can be said about IDisposable and GC, there are a few that I want to get out of the way first.&amp;#160; First of all, the GC does not care about IDisposable &lt;u&gt;at all&lt;/u&gt;!&amp;#160; It is simply not aware of whether your class implements IDisposable or not.&amp;#160; That said, many classes that implement IDisposable also implement a finalizer (discussed later), of which the GC is intimately aware.&lt;/p&gt;&lt;h3&gt;Garbage Collection&lt;/h3&gt;&lt;p&gt;First, before I go too far, let me make a brief description (simplified, of course) of the garbage collector and the process it follows to collect your unused objects.&amp;#160; Basically put, you go along happily creating new objects from the managed heap, and the GC follows behind you and computes which of those objects are no longer 'reachable' from your program and cleans up after you.&lt;/p&gt;&lt;p&gt;The GC divides the garbage collection process into stages, called &amp;quot;generations&amp;quot;.&amp;#160; All objects start their lifetime in generation 0.&amp;#160; Objects that &amp;quot;survive&amp;quot; a GC in generation 0 move to generation 1.&amp;#160; Those that survive generation 1 move to generation 2.&amp;#160; Earlier generations are collected more frequently than later generations.&lt;/p&gt;&lt;p&gt;The collection pass is actually two passes - the marking pass, and the reclamation (collection) pass.&amp;#160; The marking pass is where the GC goes through all GC roots in the application and marks 'reachable' objects and all objects reachable from them as &amp;quot;live&amp;quot;.&amp;#160; The collection pass is where the GC goes through all objects in the generation(s) being collected and frees those objects that aren't being collected (it may also relocate objects to compact memory if it decides this is useful).&lt;/p&gt;&lt;p&gt;There's a bit more complexity to it when finalizers are involved.&amp;#160; When an 'unmarked' object to be collected contains a finalizer that hasn't been suppressed using GC.SuppressFinalize(this) (presumably in IDisposable.Dispose) then the object is not freed, but rather is moved from the finalization queue to the freachable queue - and is marked (and all objects reachable from it are also marked).&amp;#160; Obviously the computation is done in a way that makes sense, not iteratively as it sounds from my description, but that complexity is not important to our discussion.&lt;/p&gt;&lt;p&gt;For more information on the GC, I recommend Jeffrey Richter's &lt;a href="http://www.amazon.com/CLR-via-Second-Pro-Developer/dp/0735621632" target="_blank"&gt;CLR via C#&lt;/a&gt;, an excellent book on this and many other topics related to advanced .NET programming.&amp;#160; However, I would caution you against reading his &amp;quot;Weak Events&amp;quot; example in that chapter as it is wrong (my next blog post will describe why and how to detect the invalidity of his approach).&amp;#160; Also, there are several blogs that are good for GC and other debugging bits, such as &lt;a href="http://blogs.msdn.com/maoni" target="_blank"&gt;Maoni&lt;/a&gt;'s or &lt;a href="http://blogs.msdn.com/Tess" target="_blank"&gt;Tess&lt;/a&gt;'s blogs.&amp;#160; A good start might be Tess's post &lt;a href="http://blogs.msdn.com/tess/archive/2008/04/17/how-does-the-gc-work-and-what-are-the-sizes-of-the-different-generations.aspx" target="_blank"&gt;here&lt;/a&gt;. (special thanks to my buddy Rich Lang for his tips on resources to recommend).&lt;/p&gt;&lt;h3&gt;IDisposable and its uses&lt;/h3&gt;&lt;p&gt;There are several different reasons people might use IDisposable.&amp;#160; Of them, there are two that are the most popular and probably the only ones that &amp;quot;normal&amp;quot; developers should ever put into action.&amp;#160; The first, most obvious, use of IDisposable is when your object needs to own 'unmanaged' resources, either directly or indirectly.&amp;#160; For instance, if you're writing a .NET class that manages some resource that you obtain via a P/Invoke call to some unmanaged library and you need to &amp;quot;free&amp;quot; or &amp;quot;release&amp;quot; that resource when your object is no longer being used.&amp;#160; In this case (direct ownership of unmanaged resources), IDisposable is not strictly necessary, but a finalizer &lt;em&gt;&lt;strong&gt;is absolutely necessary&lt;/strong&gt;&lt;/em&gt;.&amp;#160; If the object you're trying to manage is a Win32 handle (closed by CloseHandle), you should probably look at the SafeWaitHandle and SafeFileHandle classes, as well as the SafeHandleMinusOneIsInvalid and SafeHandleZeroOrMinusOneIsInvalid classes.&lt;/p&gt;&lt;p&gt;The other popular use of IDisposable is for RAII (a C++ concept - &amp;quot;resource acquisition is initialization&amp;quot;, whereby a resource is acquired as a constructor call, and released when it goes out of scope - i.e. a using statement body).&amp;#160; An example of this usage is the TransactionScope object, where you acquire the transaction by &amp;quot;newing up&amp;quot; a TransactionScope object (in a C# &amp;quot;using&amp;quot;), and you release it when you exit the using statement.&lt;/p&gt;&lt;p&gt;I'll take these two uses in turn.&lt;/p&gt;&lt;h4&gt;Resource Ownership&lt;/h4&gt;&lt;p&gt;I call the first of the two use cases for IDisposable &amp;quot;Resource Ownership&amp;quot; as your object is the consumer of some resource either directly or indirectly and should free those resources when applicable.&amp;#160; There are two forms of resource ownership, direct and indirect.&amp;#160; Direct is, as it sounds, when your object has direct ownership over a resource.&amp;#160; If the resource is unmanaged (that's really what we're talking about here), you &lt;strong&gt;&lt;em&gt;must&lt;/em&gt;&lt;/strong&gt; implement a finalizer for your object, and in that finalizer you should dispose of the resource.&amp;#160; Also, since your finalizer is only executed when your object is collected, it's generally a good idea to give users of your object the opportunity to release the resource 'early'.&amp;#160; For this reason, you implement IDisposable and the &lt;em&gt;disposal pattern &lt;/em&gt;(described below).&lt;/p&gt;&lt;p&gt;If, on the other hand, you only have &lt;em&gt;indirect&lt;/em&gt; ownership of unmanaged resources, you don't need a finalizer.&amp;#160; Instead, you should only provide the IDisposable interface and implement the &lt;em&gt;disposal pattern&lt;/em&gt;.&amp;#160; If you provide a finalizer when it isn't needed, you will, in effect, be delaying the GC cleanup of your object unnecessarily, since objects with finalizers survive &lt;u&gt;at least&lt;/u&gt; two collections after they are freed, if not more.&lt;/p&gt;&lt;h4&gt;RAII in C#&lt;/h4&gt;&lt;p&gt;I refer to the second of the two cases for IDisposable as &amp;quot;Resource Acquisition&amp;quot;.&amp;#160; The canonical example for this is TransactionScope, in my mind, but another example is a Mutex acquisition class (not to be confused with the FCL's Mutex class) or any other similar class.&amp;#160; These classes can make your code much easier to maintain and read if used properly, but can introduce some very difficult to detect bugs if used improperly, so use them with caution.&amp;#160; For this use of IDisposable, you aren't really using IDisposable because you &lt;em&gt;own&lt;/em&gt; resources, but rather because you're building a class that should have &lt;em&gt;acquire/release&lt;/em&gt; semantics and the syntax for doing so with C#'s &amp;quot;using&amp;quot; statement is very nice and clean.&lt;/p&gt;&lt;p&gt;There are several places where this pattern is used, TransactionScope is the one that comes to mind for me in the FCL, but Oren (Ayende Rahien) uses this pattern in Rhino Mocks and you see it in several other frameworks.&amp;#160; Jeffrey Richter describes it in his book in the chapter on memory management, and makes the recommendation that if you are building a library to be used by others outside of your production code, you should make your RAII (my name, not his) objects reference types, but if you are using them only internally, they can be made very efficient through the use of value types that implement IDisposable.&amp;#160; If you are writing these types for libraries, you should take great care to ensure that they free the resources they own &lt;em&gt;at most&lt;/em&gt; once, and should think very carefully about whether these types need a finalizer (I believe the jury is out on this one, but I'd say they do and should implement the &lt;em&gt;disposal pattern&lt;/em&gt; just as if they were managing a unmanaged resource).&lt;/p&gt;&lt;p&gt;It should be noted that while I call this &amp;quot;RAII in C#&amp;quot; it really isn't quite the same as RAII in C++, since in C++ destructors are guaranteed to be called when the object goes out of scope, whereas there's really nothing in the C# language / compiler that requires you put these objects in a &amp;quot;using&amp;quot; block, and thus there's nothing that guarantees that their Dispose() method gets called automatically if you choose not to use the using construct.&lt;/p&gt;&lt;h3&gt;The &lt;em&gt;disposal pattern&lt;/em&gt; and its canonical implementation&lt;/h3&gt;&lt;p&gt;Many resources describe the canonical implementation of IDisposable via the &lt;em&gt;disposal pattern, &lt;/em&gt;so I'm not going to go into excruciating detail here.&amp;#160; I'll describe the basics of the pattern and refer the reader to other sources for exact details.&amp;#160; The core idea of the &lt;em&gt;disposal pattern&lt;/em&gt; is that there are two ways in which you might want to cleanup after your object: finalization and explicit disposal via IDisposable.Dispose.&amp;#160; If your object is one that should have a finalizer, then the &lt;em&gt;disposal pattern&lt;/em&gt; should &lt;strong&gt;absolutely&lt;/strong&gt; be followed.&amp;#160; If you don't have a finalizer, then you don't strictly need to follow the disposal pattern (often this is the case for RAII applications that don't acquire resources that will deadlock the application if they aren't released, or those that are guaranteed to be properly used - because you're writing both the object and all code that uses it).&amp;#160; Even so, you're probably best to follow the &lt;em&gt;disposal pattern&lt;/em&gt; every time you implement IDisposable and just leave the parts of the pattern empty that don't apply to your particular application.&lt;/p&gt;&lt;p&gt;The basic rules of the disposal pattern are: &lt;/p&gt;&lt;ol&gt;&lt;li&gt;finalizers should not refer to other managed objects during finalization, since those objects may have already had their finalizers called. &lt;/li&gt;&lt;li&gt;IDisposable.Dispose() should call IDisposable.Dispose on any objects owned by the implementing object that are IDisposable. &lt;/li&gt;&lt;li&gt;IDisposable.Dispose() and the finalizer should &lt;strong&gt;&lt;em&gt;BOTH&lt;/em&gt;&lt;/strong&gt; free any unmanaged resources owned by the object. &lt;/li&gt;&lt;li&gt;IDisposable.Dispose() should call GC.SupressFinalize(this) to mark the work of the finalizer as being already done. &lt;/li&gt;&lt;li&gt;if your objects have shared state, then the finalizers should have code to guarantee that two finalizers being called at the same time is thread-safe. &lt;/li&gt;&lt;li&gt;finalizers should not assume they are being called on any particular thread - therefore they &lt;strong&gt;cannot&lt;/strong&gt; access TLS (thread-local storage) in any way, shape, or form! &lt;/li&gt;&lt;li&gt;calling IDisposable.Dispose() shouldn't throw an exception if called more than once. &lt;/li&gt;&lt;li&gt;method calls to any methods other than disposal methods (or the finalizer) should throw ObjectDisposedException if Dispose (or the finalizer) has already been called. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Microsoft's recommended approach for implementing the &lt;em&gt;disposal pattern&lt;/em&gt; is to have a non-public (protected) virtual (unless your class is sealed) method called Dispose on your object that takes a boolean argument called &amp;quot;disposing&amp;quot;.&amp;#160; This method should be called both by the finalizer and by IDisposable.Dispose, and if you implement a &amp;quot;Close&amp;quot; convenience method or some other method that does the same thing as IDisposable.Dispose, that should also call this single-argument version of Dispose.&amp;#160; In this Dispose method, your class should free any unmanaged resources, and if &amp;quot;disposing&amp;quot; is true, should also call Dispose on any IDisposable members of your class.&amp;#160; It should also set a flag so you know to throw ObjectDisposedException when any of your other methods or properties are accessed.&amp;#160; Finally, the Dispose method should call GC.SuppressFinalize(this) to notify the GC that the finalizer need not be called.&amp;#160; Then, the object should implement the finalizer as a call to Dispose with disposing = false, and IDisposable.Dispose as a call to Dispose with disposing = true.&lt;/p&gt;&lt;p&gt;Sample code is as follows:&lt;/p&gt;&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; background-color: #f4f4f4"&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MyClass: IDisposable&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;   [DllImport(...)] &lt;span style="color: #008000"&gt;// assume this is correctly specified.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;extern&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Free(IntPtr handle);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; IntPtr _UnmanagedThing;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; FileStream _LogFile;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; _IsDisposed;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; MyClass(FileStream logFile, IntPtr unmanagedThing)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;   {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// check arguments and don't allow finalizer if they aren't valid.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;     GC.SupressFinalize(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(logFile == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color: #006080"&gt;&amp;quot;logFile&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(unmanagedThing == IntPtr.Zero)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(&lt;span style="color: #006080"&gt;&amp;quot;unmanaged thing is invalid!&amp;quot;&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;                                   &lt;span style="color: #006080"&gt;&amp;quot;unmanagedThing&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;     GC.ReRegisterForFinalize(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;     _UnmanagedThing = unmanagedThing;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;     _LogFile = logFile;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;   }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;virtual&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose(&lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; disposing)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;   {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// we can skip doing anything if it's already been done.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(_IsDisposed)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(disposing)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// dispose of managed resources here, since we&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;       &lt;span style="color: #008000"&gt;//   were called from IDisposable.Dispose()&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;       _LogFile.Dispose();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// make sure we know that we're disposed for other calls.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;       _IsDisposed = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  42:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// free unmanaged resources in either case (IDisposable or&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  43:&lt;/span&gt;     &lt;span style="color: #008000"&gt;//   Finalize) and make sure the finalizer doesn't get called&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  44:&lt;/span&gt;     &lt;span style="color: #008000"&gt;//   later by the GC.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  45:&lt;/span&gt;     Free(_UnmanagedThing);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  46:&lt;/span&gt;     GC.SuppressFinalize(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  47:&lt;/span&gt;   }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  48:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  49:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose() { Dispose(&lt;span style="color: #0000ff"&gt;true&lt;/span&gt;); }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  50:&lt;/span&gt;   ~MyClass() { Dispose(&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;); }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  51:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  52:&lt;/span&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; DoSomething()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  53:&lt;/span&gt;   {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  54:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// some function not related to disposal of the object,&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  55:&lt;/span&gt;     &lt;span style="color: #008000"&gt;//   but requiring valid state...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  56:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(_IsDisposed)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  57:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ObjectDisposedException();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  58:&lt;/span&gt;   }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  59:&lt;/span&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Again, if you are working with a handle that is typical of Win32, you should look at the classes mentioned above (SafeHandle and it's family of derived-classes) as they do much of the work for you.&amp;#160; You should also probably have a look at CriticalFinalizerObject as well, and the MSDN topic &amp;quot;Safe Handles and Critical Finalization&amp;quot;, especially if you expect your code to be run in a hosted environment other than traditional .NET applications (i.e. IIS7, COM+, SQL Server, etc.).&lt;/p&gt;&lt;h3&gt;So what's the point?&lt;/h3&gt;&lt;p&gt;So, now, as I reread the beginning of my blog post, I wonder - what was the point I was trying to make?&amp;#160; Well, it's basically this - the use of IDisposable to dispose of objects early is an optimization, assuming the &lt;em&gt;disposal pattern&lt;/em&gt; was correctly implemented by author of the objects you are calling.&amp;#160; That is, unless you are calling RAII-style objects, in which case forgetting to call Dispose and not using these objects in a using block could be disastrous to your program.&amp;#160; On the other hand, there are several cases where it's extremely important to dispose of objects as soon as you are done with them, for instance when dealing with SqlConnection.&amp;#160; &lt;/p&gt;&lt;p&gt;On the other hand, there are plenty of objects that are fine to allow GC to collect them and &amp;quot;finalize&amp;quot; them, and there is little or no perf impact to doing so (possibly even a positive impact of not forcing early cleanup).&amp;#160; As a for-instance, consider a managed class that wraps an unmanaged resource that is not subject to contention (like some sort of unmanaged object in a library that is using the C/C++ heap to allocate these objects).&amp;#160; If you create a large number of these objects, but are not at risk of running out of memory, it can be much faster to allow the GC to collect these objects (through finalization) than having your code call Dispose on all of them and forcing early cleanup (forcing the application to incur the cost of freeing this unmanaged memory on your user threads instead of the finalizer thread).&lt;/p&gt;&lt;p&gt;As with any of my posts and most of the advice on the CLR in general, the most important takeaway from this blog post should be &amp;quot;learn the details and use your own judgement&amp;quot;.&amp;#160; Happy coding.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-5780639808044364611?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/5780639808044364611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=5780639808044364611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5780639808044364611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5780639808044364611'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2009/01/idisposable-and-garbage-collection.html' title='IDisposable and Garbage Collection'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-5280629136758323329</id><published>2009-01-23T00:21:00.001-08:00</published><updated>2009-01-23T00:33:52.455-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mutex'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='App Isolation'/><title type='text'>Detecting if other instances of your app are running.</title><content type='html'>&lt;p&gt;I got a question from a friend of mine the other day about why Process.GetProcesses() was returning an error when used under Terminal Services by a user that doesn't have the Debug Programs privilege.  It was because Process.GetProcesses() was trying to return the list of ALL processes running on the machine (including those not started by the current user).  This worked just fine when a single user was logged into the TS server, but when more than one user was logged in it failed.  My friend was very confused by this, until I told him that non-admin users need the Debug Programs privilege in order to open the process token of a process not created in their session.&lt;/p&gt;  &lt;p&gt;Of course, his next question was "how do I get Process.GetProcesses() to return only the processes accessible to the current user's session?".  At that point I took a step back and asked "why?".&lt;/p&gt;  &lt;p&gt;In fact, what he was trying to do was to detect whether another instance of his application was running, in order to gracefully tell the user that only one instance of the program can run at a time.  I asked him why he wasn't using a Mutex and the answer surprised me, just a bit.  He said "we were worried about what would happen if the process unexpectedly exited".  My next question was yet another "why?".&lt;/p&gt;  &lt;p&gt;Apparently there's some confusion about how Mutexes work in Windows, as well as how the Mutex method that I've used for about 10 years to detect multiple instances of an app works.  I'm not sure where I first learned this technique from, but I've been using it since my Win32 programming days and it's worked like a charm ever since then.  I've now used it in several reincarnations (from VB6, Delphi, C++, and now .NET) and it's never failed me.&lt;/p&gt;  &lt;p&gt;The first misconception that almost everyone has when hearing about this approach is that it has something to do with Mutexes (at least in the way they are used in multithreaded programs).  In fact, any Kernel named object could be used for this approach, including even a "delete on close" file.  However, I've always used mutexes because that's what was recommended to me, and I don't think it makes much difference since you never actually 'wait' on the mutex so it's not really important what type of object it is.  The idea of this technique is not to use a mutex, but to use the 'kernel namespace'.  Essentially, by creating a mutex in the naming scope appropriate for your purposes, you are 'registering' that name with the OS.  Then, if you were the first one to register the name, you continue, otherwise you show your message and quit.&lt;/p&gt;&lt;p&gt;The pattern looks like this:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;bool &lt;/span&gt;&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#2b91af;"&gt;MutexSecurity &lt;/span&gt;&lt;span style="color:#010001;"&gt;ms &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MutexSecurity&lt;/span&gt;();&lt;br /&gt;&lt;span style="color:#2b91af;"&gt;MutexAccessRule &lt;/span&gt;&lt;span style="color:#010001;"&gt;mar &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MutexAccessRule&lt;/span&gt;(&lt;br /&gt;  &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;SecurityIdentifier&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;WellKnownSidType&lt;/span&gt;.&lt;span style="color:#010001;"&gt;WorldSid&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;),&lt;br /&gt;  &lt;span style="color:#2b91af;"&gt;MutexRights&lt;/span&gt;.&lt;span style="color:#010001;"&gt;FullControl&lt;/span&gt;,&lt;br /&gt;  &lt;span style="color:#2b91af;"&gt;AccessControlType&lt;/span&gt;.&lt;span style="color:#010001;"&gt;Allow&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#010001;"&gt;ms&lt;/span&gt;.&lt;span style="color:#010001;"&gt;AddAccessRule&lt;/span&gt;(&lt;span style="color:#010001;"&gt;mar&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#2b91af;"&gt;Mutex &lt;/span&gt;&lt;span style="color:#010001;"&gt;m &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Mutex&lt;/span&gt;(&lt;br /&gt;  &lt;span style="color:blue;"&gt;false&lt;/span&gt;,&lt;br /&gt;  &lt;span style="color:#a31515;"&gt;@"Global\somenameuniquetomyapplication"&lt;/span&gt;,&lt;br /&gt;  &lt;span style="color:blue;"&gt;out &lt;/span&gt;&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;,&lt;br /&gt;  &lt;span style="color:#010001;"&gt;ms&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt;(!&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color:green;"&gt;// show a message that only one instance is allowed and exit&lt;br /&gt;  &lt;/span&gt;&lt;span style="color:blue;"&gt;return&lt;/span&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;where the first part (the MutexSecurity stuff) guarantees that anybody can access the mutex (the security probably doesn't need FullControl, but I didn't want to think about what it really wants, so I left it at that, no real security risk here since the only thing that could happen is other apps could grab hold of this mutex and use it for their own purposes, but that's not really going to do much).  The point of this is that the other instances of your app may not be started by the same user - this guarantees that only one app per machine is startable (because I'm using the Global namespace for my mutex name).  If, on the other hand, you want a per-session limit of a single instance (rather than per-machine) you could use the local namespace (change Global\ to Local\), which is local to each TS session.&lt;/p&gt;&lt;p&gt;The second part of that mess is the mutex creation code.  This code (as written) will create the mutex if it doesn't exist or return the existing one if one already exists with that name (and you have permissions to open it).  If you created it (because it didn't exist), then 'createdNew' will be set to True.  Otherwise, it will be false.  Either way, you get a valid Mutex object.&lt;/p&gt;&lt;p&gt;Then, you should keep this Mutex object alive for the lifetime of your application (i.e. save "m" in a variable that has the same lifetime as your application so that it doesn't get GCed and disappear on you).  A good way to do this is to make it a local variable in your Program.cs's main function.  When your application is done shutting down, you can close the mutex either as soon as you think it's ok for other instances to start, or let Windows reclaim the mutex for you.&lt;/p&gt;&lt;p&gt;Generally, I put this code in a separate library function that I can call from everywhere.  That function generally looks something like the following (in .NET):&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color:green;"&gt;Attempts to create an application isolation mutex, and&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &lt;/span&gt;&lt;span style="color:green;"&gt;return it to the caller.  If the caller isn't the first&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &lt;/span&gt;&lt;span style="color:green;"&gt;to create the mutex (i.e. it already exists) then we&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &lt;/span&gt;&lt;span style="color:green;"&gt;return null to indicate that the caller "lost".&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="objectName"&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;The name to use for the mutex,&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;should begin with Global\ if you want per-machine&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;isolation, or Local\ if you want per-session isolation.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;If you want per-machine/per-user isolation (slightly&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;different from per-session) then you should mangle the&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;mutex name by putting the username in it somewhere.&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;Null if the mutex already existed, or the mutex&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;if it was created by this function.  You should keep the&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;mutex in scope somewhere until you are ready to release&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;the isolation.  You shouldn't use this mutex for locking&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;///   &lt;/span&gt;&lt;span style="color:green;"&gt;or anything else - just forget it's a mutex altogether.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/returns&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDisposable &lt;/span&gt;&lt;span style="color:#010001;"&gt;GetAppIsolationHandle&lt;/span&gt;(&lt;span style="color:blue;"&gt;string &lt;/span&gt;&lt;span style="color:#010001;"&gt;objectName&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color:green;"&gt;// setup the mutex security settings.&lt;br /&gt;  &lt;/span&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;&lt;span style="color:#010001;"&gt;ms &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MutexSecurity&lt;/span&gt;();&lt;br /&gt;  &lt;span style="color:blue;"&gt;var &lt;/span&gt;&lt;span style="color:#010001;"&gt;sidWorld &lt;/span&gt;=&lt;br /&gt;      &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;SecurityIdentifier&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;WellKnownSidType&lt;/span&gt;.&lt;span style="color:#010001;"&gt;WorldSid&lt;/span&gt;, &lt;span style="color:blue;"&gt;null&lt;/span&gt;);&lt;br /&gt;  &lt;span style="color:blue;"&gt;var &lt;/span&gt;&lt;span style="color:#010001;"&gt;mar &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MutexAccessRule&lt;/span&gt;(&lt;br /&gt;      &lt;span style="color:#010001;"&gt;sidWorld&lt;/span&gt;,&lt;br /&gt;      &lt;span style="color:#2b91af;"&gt;MutexRights&lt;/span&gt;.&lt;span style="color:#010001;"&gt;FullControl&lt;/span&gt;,&lt;br /&gt;      &lt;span style="color:#2b91af;"&gt;AccessControlType&lt;/span&gt;.&lt;span style="color:#010001;"&gt;Allow&lt;/span&gt;);&lt;br /&gt;  &lt;span style="color:#010001;"&gt;ms&lt;/span&gt;.&lt;span style="color:#010001;"&gt;AddAccessRule&lt;/span&gt;(&lt;span style="color:#010001;"&gt;mar&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;  &lt;span style="color:green;"&gt;// create the mutex and return it if it's "ours".&lt;br /&gt;  &lt;/span&gt;&lt;span style="color:blue;"&gt;bool &lt;/span&gt;&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;;&lt;br /&gt;  &lt;span style="color:blue;"&gt;var &lt;/span&gt;&lt;span style="color:#010001;"&gt;mutex &lt;/span&gt;= &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Mutex&lt;/span&gt;(&lt;br /&gt;      &lt;span style="color:blue;"&gt;false&lt;/span&gt;,&lt;br /&gt;      &lt;span style="color:#010001;"&gt;objectName&lt;/span&gt;,&lt;br /&gt;      &lt;span style="color:blue;"&gt;out &lt;/span&gt;&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;,&lt;br /&gt;      &lt;span style="color:#010001;"&gt;ms&lt;/span&gt;);&lt;br /&gt;  &lt;span style="color:blue;"&gt;if &lt;/span&gt;(&lt;span style="color:#010001;"&gt;createdNew&lt;/span&gt;)&lt;br /&gt;      &lt;span style="color:blue;"&gt;return &lt;/span&gt;&lt;span style="color:#010001;"&gt;mutex&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color:green;"&gt;// return null if the mutex isn't "ours".&lt;br /&gt;  &lt;/span&gt;&lt;span style="color:blue;"&gt;return null&lt;/span&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Then, you can call this code in your Program.cs as follows:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;&lt;span style="color:#010001;"&gt;isolationHandle&lt;br /&gt;  &lt;/span&gt;= &lt;span style="color:#010001;"&gt;GetAppIsolationHandle&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;@"Global\MyApp"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;(&lt;span style="color:#010001;"&gt;isolationHandle &lt;/span&gt;== &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color:#2b91af;"&gt;MessageBox&lt;/span&gt;.&lt;span style="color:#010001;"&gt;Show&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"Sorry, only one at a time!"&lt;/span&gt;);&lt;br /&gt;  &lt;span style="color:blue;"&gt;return&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:blue;"&gt;using&lt;/span&gt;(&lt;span style="color:#010001;"&gt;isolationHandle&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color:#2b91af;"&gt;Application&lt;/span&gt;.&lt;span style="color:#010001;"&gt;EnableVisualStyles&lt;/span&gt;();&lt;br /&gt;  &lt;span style="color:#2b91af;"&gt;Application&lt;/span&gt;.&lt;span style="color:#010001;"&gt;Run&lt;/span&gt;(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Form&lt;/span&gt;());&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;which, of course, looks really nice (at least in my opinion).  If you had special "shutdown" stuff to do after Run returns, you can put that outside the using block (assuming it doesn't need to be isolated).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-5280629136758323329?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/5280629136758323329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=5280629136758323329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5280629136758323329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5280629136758323329'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2009/01/detecting-if-other-instances-of-your.html' title='Detecting if other instances of your app are running.'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1063230675683687315</id><published>2008-11-02T23:33:00.001-08:00</published><updated>2009-01-30T21:26:14.272-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MSMQ'/><title type='text'>Getting the message count from an MSMQ Queue</title><content type='html'>&lt;p&gt;While at KaizenConf (&lt;a href="http://www.kaizenconf.com"&gt;http://www.kaizenconf.com&lt;/a&gt;) today, I was attending a session held by Chris Patterson (twitter: @PhatBoyG) &amp;amp; Dru Sellers (twitter @drusellers) on ESBs and MassTransit, their ESB implementation.&lt;/p&gt;  &lt;p&gt;During the session, Dru complained that there wasn't a good way to get the message count from an MSMQ queue.&amp;#160; Of course, I was required to take that as a challenge, since that's the kind of guy I am :).&amp;#160; I found that as of the 3.0 API for MSMQ (apparently, that's the XP / Server 2003 vintage), there's a few ways to get the message count for a queue.&lt;/p&gt;  &lt;p&gt;The available methods (that I found) for asking for the count of messages in a Queue were:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Call MQMgmtGetInfo API to query the queue for the PROPID_MGMT_QUEUE_MESSAGE_COUNT property. &lt;/li&gt;    &lt;li&gt;Load up a MSMQManagement COM object, call it's Init method to associate with a Queue, and then ask for it's MessageCount property value. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It appears that the first method (which is an API call) is actually just a proxy for the second, so I'm not going to talk about it.&amp;#160; Calling the COM object from .NET is much easier than calling the API anyway, since it's not exactly a 'pretty' API for P/Invoke purposes.&lt;/p&gt;  &lt;p&gt;Since I'm not really interested in investing a lot of time in this blog post, I'm just going to paste the code here and let you do with it as you please...&amp;#160; Here goes...&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;path = &lt;span style="color: #a31515"&gt;@&amp;quot;.\Private$\foo&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #2b91af"&gt;MessageQueue &lt;/span&gt;mq = &lt;span style="color: #2b91af"&gt;MessageQueue&lt;/span&gt;.Exists(path) &lt;br /&gt;                ? &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MessageQueue&lt;/span&gt;(path) &lt;br /&gt;                : &lt;span style="color: #2b91af"&gt;MessageQueue&lt;/span&gt;.Create(path);&lt;br /&gt;&lt;span style="color: blue"&gt;try&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: green"&gt;// try to insert a few items into the queue...&lt;br /&gt;    &lt;/span&gt;mq.Send(&lt;span style="color: #a31515"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;);&lt;br /&gt;    mq.Send(&lt;span style="color: #a31515"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;);&lt;br /&gt;    mq.Send(&lt;span style="color: #a31515"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;var &lt;/span&gt;msmqMgmt = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MSMQManagement&lt;/span&gt;();&lt;br /&gt;    &lt;span style="color: blue"&gt;object &lt;/span&gt;machine = &lt;span style="color: blue"&gt;null&lt;/span&gt;; &lt;span style="color: green"&gt;// mq.MachineName;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;object &lt;/span&gt;queuename = mq.Path;&lt;br /&gt;    &lt;span style="color: blue"&gt;object &lt;/span&gt;formatname = &lt;span style="color: blue"&gt;null&lt;/span&gt;; &lt;span style="color: green"&gt;//mq.FormatName;&lt;br /&gt;    &lt;/span&gt;msmqMgmt.Init(&lt;span style="color: blue"&gt;ref &lt;/span&gt;machine, &lt;span style="color: blue"&gt;ref &lt;/span&gt;queuename, &lt;br /&gt;        &lt;span style="color: blue"&gt;ref &lt;/span&gt;formatname);&lt;br /&gt;    &lt;span style="color: blue"&gt;int &lt;/span&gt;messageCount = msmqMgmt.MessageCount;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #2b91af"&gt;MessageBox&lt;/span&gt;.Show(&lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;Queue has {0} items&amp;quot;&lt;/span&gt;, &lt;br /&gt;        messageCount));&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: blue"&gt;finally&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;string &lt;/span&gt;path2 = mq.Path;&lt;br /&gt;    mq.Close();&lt;br /&gt;    &lt;span style="color: #2b91af"&gt;MessageQueue&lt;/span&gt;.Delete(path2);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Of course, this code requires a reference to the COM type library - namely the &amp;quot;Microsoft Message Queue 3.0 Object Library&amp;quot; on the COM list in VS2008 when you have MSMQ installed on your dev box.&lt;/p&gt;&lt;p&gt;I had some weird problems trying to test this code on my machine, hence the commented machinename and formatname.&amp;#160; I think the problem was probably related more to the configuration of my machine than it was the code.&amp;#160; I suspect, however, that there may be some complexities that require you to specify machine name, queue name, and format name differently depending on whether you are working with a local queue or a remote one.&lt;/p&gt;&lt;p&gt;I found that for a local queue, the easy way to reference it was the code snippet above (don't specify machine, don't specify format name, supply the &amp;quot;path&amp;quot;).&amp;#160; For a remote queue, I suspect that it will be easier to pass the machine name, the format name, and omit (pass null for) the path.&amp;#160; Note, the API states that you should NOT pass both the format name and the path name, or it will give an exception.&lt;/p&gt;&lt;p&gt;As always, if you have questions regarding this code, please don't hesitate to contact me via the comments or my email.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1063230675683687315?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1063230675683687315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1063230675683687315' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1063230675683687315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1063230675683687315'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/11/getting-message-count-from-msmq-queue.html' title='Getting the message count from an MSMQ Queue'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1892875918555750506</id><published>2008-11-01T10:24:00.000-07:00</published><updated>2008-11-01T11:09:26.570-07:00</updated><title type='text'>.NET wish list...</title><content type='html'>&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Generics that can support 'text-like' replacement at runtime, where you can basically say that "I know that type T actually has a method called Foo with the signature bool Foo(int) but may not implement some particular interface (since you may not control the implementation of T)". I'd like to be able to call Foo from my generic class even if I can't change T to implement an interface that supports Foo. I'm thinking something like: &lt;span style="font-family:courier new;"&gt;&lt;blockquote&gt;&lt;pre&gt;public static void DoSomething&lt;t&gt;(T target)&lt;br /&gt;    where T: class having bool Foo(int)&lt;br /&gt;{&lt;br /&gt;    if(target.Foo(0))&lt;br /&gt;        Console.WriteLine("Woohoo");&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;A way of marking objects that MUST be used in a 'using' expression (i.e. they only make sense there) and having the C# compiler enforce it.  For instance, an attribute would work for me (similar to how 'FlagsAttribute' indicates special semantics on enums).  My reasoning for this is that I'd like to use IDisposable for some C++-style RAII-like stuff, but there's no way to guarantee that the objects are used correctly.&lt;/li&gt;&lt;li&gt;A way of injecting simple code / hooking "before" and "after" property notifications on 'automatic properties' in C#.  For instance, if I do an automatic property, I'd love to be able to say "any time this changes, call this method", or something like that.  It could be useful for INotifyPropertyChanged, but also for other things as well.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1892875918555750506?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1892875918555750506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1892875918555750506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1892875918555750506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1892875918555750506'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/11/net-wish-list.html' title='.NET wish list...'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-6198848529266271675</id><published>2008-08-09T00:23:00.001-07:00</published><updated>2008-08-09T00:31:07.995-07:00</updated><title type='text'>Building a WPF Grid Control (Part 2 of ?)</title><content type='html'>&lt;p&gt;So, last time (&lt;a title="Previous Post (KLeahy Technical)" href="http://kleahy-technical.blogspot.com/2008/08/building-wpf-grid-control-part-1-of.html" target="_blank"&gt;Building a WPF Grid Control (Part 1 of ?)&lt;/a&gt;) we described some of the data binding structures of our WPF grid control.  I'm not going to provide implementations of those interfaces yet, instead concentrating on some of the interesting bits of the control's implementation.  For the most part, building the control comes down to several bits of functionality - scrolling, rendering, mouse support, keyboard support, and data binding.  We've already seen the data binding part, so next I want to concentrate on scrolling.&lt;/p&gt;&lt;p&gt;Building scrolling into the UI is not terribly difficult, and for the most part, the implementation can be done without actually dealing with the data binding interfaces at all.  However, there are a few details that we need from the interfaces in order to have a go at scrolling - namely, we need to know how big the fixed and scrolling regions need to be.  Therefore, we need a dummy implementation of IDimensionMetrics that give us some sizes to play with.  Since we currently won't have fixed rows or fixed columns, and all the grid cares about for laying out the regions is the TotalSpace member of this interface, we should be able to get away with a really dumb implementation.&lt;/p&gt;&lt;p&gt;So, let's implement IDimensionMetrics as:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;IDimensionMetrics&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;private double &lt;/span&gt;_TotalSpace;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;ReallyDumbMetrics(&lt;span style="color:blue;"&gt;double &lt;/span&gt;totalSpace)&lt;br /&gt;    {&lt;br /&gt;        _TotalSpace = totalSpace;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;#region &lt;/span&gt;IDimensionMetrics Members&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public double &lt;/span&gt;GetSpace(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;SetSpace(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index, &lt;span style="color:blue;"&gt;double &lt;/span&gt;space)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public double &lt;/span&gt;GetStart(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public double &lt;/span&gt;TotalSpace&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_TotalSpace; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public int &lt;/span&gt;Count&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public event &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;EventHandler &lt;/span&gt;SpaceChanged;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;#endregion&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;p&gt;I just realized that I forgot to describe the IGridBindings interface in my last post.  This interface is very simple and is just a container for the various pieces of the bindings (selection info, dimensions, region render info) that allows a single point of binding for the grid control.  The interface is defined as:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IGridBindings&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;TopLeftRenderInfo { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;HScrollRenderInfo { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;VScrollRenderInfo { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;HVScrollRenderInfo { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;FixedRowMetrics { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;FixedColMetrics { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;ScrollingRowMetrics { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;ScrollingColMetrics { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;ISelectionInfo &lt;/span&gt;SelectionInfo { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;Reorder(&lt;span style="color:blue;"&gt;int&lt;/span&gt;[] oldPositions);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Since we'll be starting on our grid control now, it would be nice to have a IGridBindings implementation that will allow us to start working with the binding interfaces of the grid.  So, let's go with a dummy implementation of GridBindings that uses our ReallyDumbMetrics implementation above.  Here goes:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbGridBindings &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;IGridBindings&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics &lt;/span&gt;_FixedRowMetrics;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics &lt;/span&gt;_FixedColMetrics;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics &lt;/span&gt;_ScrollingRowMetrics;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics &lt;/span&gt;_ScrollingColMetrics;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;ReallyDumbGridBindings(&lt;span style="color:blue;"&gt;double &lt;/span&gt;fixedRowSize, &lt;span style="color:blue;"&gt;double &lt;/span&gt;fixedColSize, &lt;span style="color:blue;"&gt;double &lt;/span&gt;scrollRowSize, &lt;span style="color:blue;"&gt;double &lt;/span&gt;scrollColSize)&lt;br /&gt;    {&lt;br /&gt;        _FixedRowMetrics = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics&lt;/span&gt;(fixedRowSize);&lt;br /&gt;        _FixedColMetrics = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics&lt;/span&gt;(fixedColSize);&lt;br /&gt;        _ScrollingRowMetrics = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics&lt;/span&gt;(scrollRowSize);&lt;br /&gt;        _ScrollingColMetrics = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ReallyDumbMetrics&lt;/span&gt;(scrollColSize);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;#region &lt;/span&gt;IGridBindings Members&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;TopLeftRenderInfo&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;HScrollRenderInfo&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;VScrollRenderInfo&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IRegionRenderInfo &lt;/span&gt;HVScrollRenderInfo&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;FixedRowMetrics&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_FixedRowMetrics; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;FixedColMetrics&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_FixedColMetrics; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;ScrollingRowMetrics&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_ScrollingRowMetrics; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;ScrollingColMetrics&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_ScrollingColMetrics; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ISelectionInfo &lt;/span&gt;SelectionInfo&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;Reorder(&lt;span style="color:blue;"&gt;int&lt;/span&gt;[] oldPositions)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NotImplementedException&lt;/span&gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;#endregion&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;p&gt;Ok... I think we're ready to write some Grid code...&lt;/p&gt;&lt;h2&gt;Region Implementation&lt;/h2&gt;&lt;p&gt;Let's start with a simple implementation of a GridRegion base class that will provide the functionality for the four cell-containing regions in the grid UI.  This class will derive from FrameworkElement just as our Grid does, and will participate in the layout system as usual (measure and arrange passes).  For now, to avoid getting bogged down in the details of rendering rows and columns, we'll make it just draw big red ellipses in the regions.&lt;/p&gt;&lt;p&gt;Let's start with the GridRegion.  We can begin with the following class:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;GridRegion&lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;FrameworkElement&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;GridRegion()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Now, for any FrameworkElement, we need to support Measure and Arrange layout passes.  We also need to support the dimension metrics in order to obtain the sizes for our control.  The dimension metrics additions to GridRegion will be:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;_RowMetrics;&lt;br /&gt;&lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;_ColMetrics;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;_ReplaceMetrics(&lt;span style="color:blue;"&gt;ref &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;target, &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;source)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(target != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;        target.SpaceChanged -= Metrics_SpaceChanged;&lt;br /&gt;    target = source;&lt;br /&gt;    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(target != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;        target.SpaceChanged += Metrics_SpaceChanged;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;SetBindings(&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;rowMetrics, &lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;colMetrics)&lt;br /&gt;{&lt;br /&gt;    _ReplaceMetrics(&lt;span style="color:blue;"&gt;ref &lt;/span&gt;_RowMetrics, rowMetrics);&lt;br /&gt;    _ReplaceMetrics(&lt;span style="color:blue;"&gt;ref &lt;/span&gt;_ColMetrics, colMetrics);&lt;br /&gt;    InvalidateMeasure();&lt;br /&gt;    InvalidateVisual();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;Metrics_SpaceChanged(&lt;span style="color:blue;"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af;"&gt;EventArgs &lt;/span&gt;e)&lt;br /&gt;{&lt;br /&gt;    InvalidateMeasure();&lt;br /&gt;    InvalidateVisual();&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The basic idea here is the SetBindings method, used by the EditorGrid (that owns the GridRegion objects) to initialize the RowMetrics and ColMetrics properties.  Each time the Bindings property of the EditorGrid is changed (it's the property that holds the IGridBindings interface reference) the grid will call SetBindings on each of the four regions.&lt;/p&gt;&lt;p&gt;We also need to support the layout and arrange passes for our control.  Our container (the grid) will decide the layout of our control, all we need to do is request as much space as it is willing to give us (by returning availableSize from the MeasureOverride method as follows).&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;MeasureOverride(&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;availableSize)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;return &lt;/span&gt;availableSize;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;This same functionality could possibly be achieved in another way, but this was the easiest way that I found.  I suspect that setting the alignment properties to 'stretch' might have worked, but it didn't seem to (or at least I don't remember it working when I thought I tried it).&lt;/p&gt;&lt;h2&gt;Grid Implementation&lt;/h2&gt;&lt;p&gt;Ok, we can now start implementing the grid control itself.  Let's start with this class, similar to the GridRegion we just completed:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;EditorGrid&lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;FrameworkElement&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;GridRegion &lt;/span&gt;_TopLeftNonScroll;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;GridRegion &lt;/span&gt;_HScrollRegion;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;GridRegion &lt;/span&gt;_VScrollRegion;&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;GridRegion &lt;/span&gt;_HVScrollRegion;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;EditorGrid()&lt;br /&gt;    {&lt;br /&gt;        _TopLeftNonScroll = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;GridRegion&lt;/span&gt;();&lt;br /&gt;        _HScrollRegion = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;GridRegion&lt;/span&gt;();&lt;br /&gt;        _VScrollRegion = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;GridRegion&lt;/span&gt;();&lt;br /&gt;        _HVScrollRegion = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;GridRegion&lt;/span&gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IGridBindings &lt;/span&gt;_Bindings;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IGridBindings &lt;/span&gt;Bindings&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_Bindings; }&lt;br /&gt;        &lt;span style="color:blue;"&gt;set&lt;br /&gt;        &lt;/span&gt;{&lt;br /&gt;            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_Bindings != &lt;span style="color:blue;"&gt;value&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_Bindings != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    _Bindings.FixedColMetrics.SpaceChanged -= Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.FixedRowMetrics.SpaceChanged -= Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.ScrollingColMetrics.SpaceChanged -= Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.ScrollingRowMetrics.SpaceChanged -= Metrics_SpaceChanged;&lt;br /&gt;                }&lt;br /&gt;                _Bindings = &lt;span style="color:blue;"&gt;value&lt;/span&gt;;&lt;br /&gt;                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_Bindings != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    _Bindings.FixedColMetrics.SpaceChanged += Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.FixedRowMetrics.SpaceChanged += Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.ScrollingColMetrics.SpaceChanged += Metrics_SpaceChanged;&lt;br /&gt;                    _Bindings.ScrollingRowMetrics.SpaceChanged += Metrics_SpaceChanged;&lt;br /&gt;                }&lt;br /&gt;                _TopLeftNonScroll.SetBindings(_Bindings.FixedRowMetrics, _Bindings.FixedColMetrics);&lt;br /&gt;                _HScrollRegion.SetBindings(_Bindings.FixedRowMetrics, _Bindings.ScrollingColMetrics);&lt;br /&gt;                _VScrollRegion.SetBindings(_Bindings.ScrollingRowMetrics, _Bindings.FixedColMetrics);&lt;br /&gt;                _HVScrollRegion.SetBindings(_Bindings.ScrollingRowMetrics, _Bindings.ScrollingColMetrics);&lt;br /&gt;&lt;br /&gt;                InvalidateMeasure();&lt;br /&gt;                InvalidateVisual();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;Metrics_SpaceChanged(&lt;span style="color:blue;"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af;"&gt;EventArgs &lt;/span&gt;e)&lt;br /&gt;    {&lt;br /&gt;        InvalidateMeasure();&lt;br /&gt;        InvalidateVisual();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;As you can see, the bindings on the regions are set to different metrics depending on their locations in the grid.  The TopLeftNonScroll region uses 'Fixed' metrics for both rows and columns, the HScrollRegion uses 'Scrolling' for columns and 'Fixed' for rows, and so on.&lt;/p&gt;&lt;p&gt;We now need to discuss the layout of the children of the editor grid.  We also need to add scrollbars and the other non-cellular regions.  For the moment, we'll ignore the other regions and the scrollbars.  Let's just get the cellular regions in place first.  In order to do all the layout stuff, we'll create a helper class that will make things easier for us.  I'll call this class LayoutMetrics and define it as follows:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LayoutMetrics&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;vscroll_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;hscroll_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;hscrollR_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;vscrollR_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;hvscrollR_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;topleft_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;topright_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;botleft_rect;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;botright_rect;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;LayoutMetrics(&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;size, &lt;span style="color:blue;"&gt;double &lt;/span&gt;vscroll_width, &lt;span style="color:blue;"&gt;double &lt;/span&gt;hscroll_height, &lt;span style="color:blue;"&gt;double &lt;/span&gt;fixedRowHeight, &lt;span style="color:blue;"&gt;double &lt;/span&gt;fixedColWidth)&lt;br /&gt;    {&lt;br /&gt;        vscroll_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(size.Width - vscroll_width,&lt;br /&gt;                fixedRowHeight,&lt;br /&gt;                vscroll_width,&lt;br /&gt;                &lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Max(0, size.Height - hscroll_height - fixedRowHeight));&lt;br /&gt;&lt;br /&gt;        hscroll_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(fixedColWidth,&lt;br /&gt;                size.Height - hscroll_height,&lt;br /&gt;                &lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Max(0, size.Width - vscroll_width - fixedColWidth),&lt;br /&gt;                hscroll_height);&lt;br /&gt;&lt;br /&gt;        hscrollR_rect = hscroll_rect;&lt;br /&gt;        hscrollR_rect.Y = 0;&lt;br /&gt;        hscrollR_rect.Height = fixedRowHeight + 1;&lt;br /&gt;&lt;br /&gt;        vscrollR_rect = vscroll_rect;&lt;br /&gt;        vscrollR_rect.X = 0;&lt;br /&gt;        vscrollR_rect.Width = fixedColWidth + 1;&lt;br /&gt;&lt;br /&gt;        hvscrollR_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(hscroll_rect.X, vscroll_rect.Y,&lt;br /&gt;                hscroll_rect.Width, vscroll_rect.Height);&lt;br /&gt;&lt;br /&gt;        topleft_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Size&lt;/span&gt;(fixedColWidth + 1, fixedRowHeight + 1));&lt;br /&gt;        topright_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(vscroll_rect.X, 0, vscroll_rect.Width, hscrollR_rect.Height - 1);&lt;br /&gt;        botleft_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(0, hscroll_rect.Y, vscrollR_rect.Width - 1, hscroll_rect.Height);&lt;br /&gt;        botright_rect =&lt;br /&gt;            &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(vscroll_rect.X, hscroll_rect.Y, vscroll_rect.Width, hscroll_rect.Height);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The main idea of this class is to break the space occupied by the Grid into the component rectangles.  For now, we'll supply some dummy values for the sizes of the horizontal and vertical scrollbars.  Now, given this class, we can implement our 'measure' and 'arrange' methods for the WPF layout system.  We do so (on our EditorGrid class) as follows:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;MeasureOverride(&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;availableSize)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:green;"&gt;// for now, fake the sizes of the scroll bars just to reserve some space.&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LayoutMetrics &lt;/span&gt;m = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LayoutMetrics&lt;/span&gt;(availableSize,&lt;br /&gt;        14, &lt;span style="color:green;"&gt;// vscroll_width&lt;br /&gt;        &lt;/span&gt;14, &lt;span style="color:green;"&gt;// hscroll_width&lt;br /&gt;        &lt;/span&gt;_Bindings.FixedRowMetrics.TotalSpace,&lt;br /&gt;        _Bindings.FixedColMetrics.TotalSpace);&lt;br /&gt;&lt;br /&gt;    _TopLeftNonScroll.Measure(m.topleft_rect.Size);&lt;br /&gt;    _HScrollRegion.Measure(m.hscrollR_rect.Size);&lt;br /&gt;    _VScrollRegion.Measure(m.vscrollR_rect.Size);&lt;br /&gt;    _HVScrollRegion.Measure(m.hvscrollR_rect.Size);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;return &lt;/span&gt;availableSize;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;ArrangeOverride(&lt;span style="color:#2b91af;"&gt;Size &lt;/span&gt;finalSize)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:green;"&gt;// for now, fake the sizes of the scroll bars just to reserve some space.&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LayoutMetrics &lt;/span&gt;m = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LayoutMetrics&lt;/span&gt;(finalSize,&lt;br /&gt;        14, &lt;span style="color:green;"&gt;// vscroll_width&lt;br /&gt;        &lt;/span&gt;14, &lt;span style="color:green;"&gt;// hscroll_width&lt;br /&gt;        &lt;/span&gt;_Bindings.FixedRowMetrics.TotalSpace,&lt;br /&gt;        _Bindings.FixedColMetrics.TotalSpace);&lt;br /&gt;&lt;br /&gt;    _TopLeftNonScroll.Arrange(m.topleft_rect);&lt;br /&gt;    _HScrollRegion.Arrange(m.hscrollR_rect);&lt;br /&gt;    _VScrollRegion.Arrange(m.vscrollR_rect);&lt;br /&gt;    _HVScrollRegion.Arrange(m.hvscrollR_rect);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;return &lt;/span&gt;finalSize;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Now, we need to add visual tree support to our grid control.  In order to do this, we need a few features - first, we need to add the regions to the visual tree by calling AddVisualChild on our grid visual.  Second, we need to override the 'render list' method &amp;amp; property GetVisualChild and VisualChildrenCount respectively.  The first (calling AddVisualChild) we do by adding the following lines to the constructor (after the creation of the regions):&lt;/p&gt;&lt;pre class="code"&gt;AddVisualChild(_TopLeftNonScroll);&lt;br /&gt;AddVisualChild(_HScrollRegion);&lt;br /&gt;AddVisualChild(_VScrollRegion);&lt;br /&gt;AddVisualChild(_HVScrollRegion);&lt;/pre&gt;&lt;p&gt;Now that we have those lines in the constructor, we need to implement the 'rendering' functionality.  The easiest way to do this is either with a VisualCollection, or since in our case we have a fixed list, just an array of Visuals.  The GetVisualChild method must return visuals in the order in which they should be rendered, and we want our regions to render in the following order: HVScrollRegion, HScrollRegion, VScrollRegion, TopLeftNonScroll.  We will add a field to EditorGrid class that is an array of visuals (Visual[]) called _Visuals, and initialize it in the constructor (after the four lines above) as follows:&lt;/p&gt;&lt;pre class="code"&gt;_Visuals = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Visual&lt;/span&gt;[]&lt;br /&gt;{&lt;br /&gt;    _HVScrollRegion,&lt;br /&gt;    _HScrollRegion,&lt;br /&gt;    _VScrollRegion,&lt;br /&gt;    _TopLeftNonScroll&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;Additionally, we need to implement the GetVisualChild method and VisualChildrenCount property as follows:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Visual &lt;/span&gt;GetVisualChild(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;return &lt;/span&gt;_Visuals[index];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;protected override int &lt;/span&gt;VisualChildrenCount&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_Visuals.Length; }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;We now need to implement rendering in our GridRegion and then we'll have something we can start messing with.  Here's the implementation of the OnRender method for the GridRegion control.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;protected override void &lt;/span&gt;OnRender(&lt;span style="color:#2b91af;"&gt;DrawingContext &lt;/span&gt;drawingContext)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_RowMetrics == &lt;span style="color:blue;"&gt;null &lt;/span&gt; _ColMetrics == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;        &lt;span style="color:blue;"&gt;return&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;double &lt;/span&gt;xmid = _ColMetrics.TotalSpace / 2;&lt;br /&gt;    &lt;span style="color:blue;"&gt;double &lt;/span&gt;ymid = _RowMetrics.TotalSpace / 2;&lt;br /&gt;&lt;br /&gt;    drawingContext.PushClip(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;RectangleGeometry&lt;/span&gt;(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(RenderSize)));&lt;br /&gt;    drawingContext.DrawEllipse(&lt;span style="color:#2b91af;"&gt;Brushes&lt;/span&gt;.Red, &lt;span style="color:blue;"&gt;null&lt;/span&gt;, &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Point&lt;/span&gt;(xmid, ymid), xmid, ymid);&lt;br /&gt;    drawingContext.Pop();&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Next time, we'll work on getting some scrolling features working.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-6198848529266271675?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/6198848529266271675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=6198848529266271675' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6198848529266271675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6198848529266271675'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/08/building-wpf-grid-control-part-2-of.html' title='Building a WPF Grid Control (Part 2 of ?)'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-2982990669662406993</id><published>2008-08-01T13:21:00.001-07:00</published><updated>2008-08-09T00:33:36.073-07:00</updated><title type='text'>Building a WPF Grid Control (Part 1 of ?)</title><content type='html'>&lt;p&gt;So, some of you may know that I'm building a Grid control for our MG-ALFA application.  We started by looking at the WPF grids out there, and found that none of them really fit our needs.  There were several issues with the controls on the market.  Much of what we wanted was very 'simple', as far as look &amp;amp; feel (like a traditional grid), yet all the WPF grids on the market seemed to be focused on 'pretty'.  Also, we needed to be able to customize several very specific features - for instance, we wanted dragging of columns for reordering, fixed rows &amp;amp; columns, and the ability to easily transpose the grid.&lt;/p&gt;&lt;p&gt;None of these features were easy to come by in existing controls, and in order to get an of them, we would have to heavily customize the controls out of the box.  The customization would be 'on top' of the control, so there wasn't a good way to tie it to our data model, and transpose was the killer feature.  In order to get transpose, we would have had to write some really nasty code and do some really unpleasant things with databinding.  If we didn't do those nasty things, we'd have to use 'unbound' mode on the controls, which would lead to really unpleasant code to keep the grid in sync with the data changes.&lt;/p&gt;&lt;p&gt;Finally, after a ton of investigation, we decided we'd be better off just writing our own control and building a truly custom data model for the grid, rather than trying to force fit an existing control to our problem.  We were very skeptical about the amount of time it would take to build a grid that had the features we needed, but I was pretty sure it would be less than a few weeks, and it turns out I was mostly right about that.  I'm going to try to describe the design of the control, from the ground up, in a series of blog posts, but I hope you'll ask questions if you want more details, as I undoubtedly won't cover everything.&lt;/p&gt;&lt;p&gt;So, first, let's talk about the basic design of the grid, and the features we required.  The grid is built on WPF mostly using visual layer programming to do the rendering.  It supports fixed rows, fixed columns, and has row and column headings.  Visually it looks very much like MS Excel.  The UX is also intended to be very much like Excel, except with some modifications that are specific to our domain needs (and no support for formulas).&lt;/p&gt;&lt;h2&gt;What to derive from?&lt;/h2&gt;&lt;p&gt;The first decision in any custom control development for WPF is to decide which of the multitude of classes you should derive from.  The class hierarchy is:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Visual&lt;br /&gt;    UIElement&lt;br /&gt;        FrameworkElement&lt;br /&gt;            Control&lt;br /&gt;                ...&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Visual is very rudimentary, and basically provides only the ability to manage and participate in the visual tree.  It is possible to build components at the 'Visual' level, but relatively difficult, and they must be built from other components that are at a higher level (at least UIElement).  This is because the only thing a Visual can effectively do is contain other Visuals, and perform hit testing.  There are a few Visual-derived classes that can be used by control designers (DrawingVisual, ContainerVisual), but these aren't really useful as base classes (maybe ContainerVisual, but certainly not DrawingVisual).&lt;/p&gt;&lt;p&gt;UIElement is effectively the lowest level class that a control designer might want to derive from.  It provides basic layout, event handling, focus support, and rendering features.  To provide code for rendering a UIElement, you must override OnRender.  You also will want to override MeasureCore and ArrangeCore to participate in the layout process.  You may also want to override HitTestCore to provide sophisticated hit testing for your control, especially if you have a non-rectangular area (our control will be rectangular and covered by other child controls, so we don't really need to mess with HitTestCore).&lt;/p&gt;&lt;p&gt;FrameworkElement is really the 'entry point' into WPF framework-level programming.  Much of the core functionality for rendering is introduced in the UIElement class, but FrameworkElement builds on these features and provides some core implementation that makes it easier for you to implement the layout methods (i.e. it handles things like HorizontalAlignment, VerticalAlignment, Width, Height, etc., so you don't have to write the tedious code to make these work in your MeasureCore and ArrangeCore implementations).  It also provides the core functionality needed for data binding.  We'll derive our grid control from FrameworkElement, because it's the lowest class we can derive from without making a ton of extra work for ourselves, and it's the highest class we can effectively derive from without introducing features we don't want.&lt;/p&gt;&lt;p&gt;Control introduces style and templating support.  Since we specifically don't want the XAML user to be able to customize the control template and styles for our grid (we want very specific control over how things are rendered), and don't need the flexibility that styles and templates provide, we don't want Control.  However, it should be noted that if you want to build the 'best' control, from a flexibility standpoint, you probably do want to provide these features and use the 'recommended' approach of deriving from something at the Control or higher levels of the inheritance tree.&lt;/p&gt;&lt;h2&gt;Visual Layout&lt;/h2&gt;&lt;p&gt;Our grid control looks like the screenshot below (currently).  It is still a work in progress, and that's why those ugly orange sections are there, and why the fixed rows look kinda funny (no gridlines, green background, etc.).&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/kelly.p.leahy/SJNwQM07xgI/AAAAAAAAABE/_mR_DEDwWQk/image%5B6%5D.png"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="400" alt="image" src="http://lh6.ggpht.com/kelly.p.leahy/SJNwQtHUAuI/AAAAAAAAABM/P8NMwa_Dphg/image_thumb%5B4%5D.png" width="508" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Obviously the data I've been working with is dummy data, generated by my data source for my benefit during development.&lt;/p&gt;&lt;p&gt;My first step in building the control was to design the layout of the control, in terms of separate 'regions' of the grid, based on their scrolling nature, and based on the relative positions of the scrolling regions.  In the picture below, I've labeled the 9 independent regions of the grid control.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/kelly.p.leahy/SJNwRMFR_AI/AAAAAAAAABQ/-xfJd98KNOU/image%5B18%5D.png"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="378" alt="image" src="http://lh4.ggpht.com/kelly.p.leahy/SJNwRcZ7DQI/AAAAAAAAABU/RXaOItDteb4/image_thumb%5B12%5D.png" width="512" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The regions, in left-to-right (top-to-bottom) order are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;TopLeftNonScroll - the fixed row/fixed column intersection, including the "select all" box.&lt;/li&gt;&lt;li&gt;HScrollRegion - the horizontal-only scrolling region (fixed rows, scrolling columns).&lt;/li&gt;&lt;li&gt;TopRightNonScroll - the area above the vertical scroll bar, that doesn't scroll and will eventually house buttons or some other visual cue / support.&lt;/li&gt;&lt;li&gt;VScrollRegion - the vertical-only scrolling region (fixed columns, scrolling rows).&lt;/li&gt;&lt;li&gt;HVScrollRegion - the 'data' section of the grid.  This area scrolls both directions, and is made up of the scrolling rows / scrolling columns intersection.&lt;/li&gt;&lt;li&gt;VScrollBar - the vertical scroll bar (a ScrollBar control with its Orientation set to Orientation.Vertical)&lt;/li&gt;&lt;li&gt;BottomLeftNonScroll - the non scrolling area to the left of the horizontal scroll bar, will eventually be another place for buttons, etc.&lt;/li&gt;&lt;li&gt;HScrollBar - the horizontal scroll bar (a ScrollBar control with its Orientation set to Orientation.Horizontal).&lt;/li&gt;&lt;li&gt;BottomRightNonScroll - this will likely just be a gray 'dead-zone' so the scroll bars don't look stupid.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For the most part, except for scrolling, the HScrollRegion, TopLeftNonScroll, VScrollRegion, and HVScrollRegion have the same UI / UX, so I've combined much of the functionality into a single base class called "GridRegion".  It has some parameterized options (like which directions it can scroll), but for the most part the code is all shared and used from this class.  The derived classes are generally pretty small, and are just responsible for 'customizing' the GridRegion functionality.&lt;/p&gt;&lt;p&gt;The other regions are currently implemented just as canvases (except the ScrollBars, of course).&lt;/p&gt;&lt;h2&gt;Data Binding model&lt;/h2&gt;&lt;p&gt;My data binding model has several parts.  The entire model is really a 'view' from the standpoint of MVP-like design patterns (at least in my assessment it is).  The real data model is specific to the application.  The Data Binding model supported by the grid has bindings for the selection and active / anchor cells, the row &amp;amp; column sizes, and the contents of the cells (including render flags and other special items).&lt;/p&gt;&lt;p&gt;In order to simplify the design and implementation, I've separated the binding into several objects based on the way the regions break up the grid.  The major breakdown is between dimension metrics, render info, and selection support.&lt;/p&gt;&lt;h3&gt;Dimension Metrics (sizes of rows / columns)&lt;/h3&gt;&lt;p&gt;For the dimensions of the rows and columns, I've defined an interface called IDimensionMetrics that allows management of and provides information about the sizes of rows or columns.  It is defined as follows.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;double &lt;/span&gt;GetSpace(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index);&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SetSpace(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index, &lt;span style="color:blue;"&gt;double &lt;/span&gt;space);&lt;br /&gt;    &lt;span style="color:blue;"&gt;double &lt;/span&gt;GetStart(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index);&lt;br /&gt;    &lt;span style="color:blue;"&gt;double &lt;/span&gt;TotalSpace { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;Count { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;event &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;EventHandler &lt;/span&gt;SpaceChanged;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Each object that implements IDimensionMetrics only represents a single group of rows or columns.  There are 4 implementations of IDimensionMetrics for a single set of grid bindings.  The columns are broken into "fixed" and "scrolling", as are the rows (for a total of 4 separate groups).&lt;/p&gt;&lt;p&gt;In order to provide some additional features for IDimensionMetrics without requiring that all implementers implement these features, I've used some extension methods to implement common algorithms based on IDimensionMetrics.  The extension class is as follows.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DimensionExtensions&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;public static double &lt;/span&gt;GetEnd(&lt;span style="color:blue;"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;metrics, &lt;span style="color:blue;"&gt;int &lt;/span&gt;index)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;return &lt;/span&gt;metrics.GetStart(index) + metrics.GetSpace(index);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public static int &lt;/span&gt;HitTestNoSizing(&lt;span style="color:blue;"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;metrics, &lt;span style="color:blue;"&gt;double &lt;/span&gt;v)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;for &lt;/span&gt;(&lt;span style="color:blue;"&gt;int &lt;/span&gt;i = 0; i &amp;lt; metrics.Count; i++)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:blue;"&gt;double &lt;/span&gt;ofs = v - metrics.GetStart(i);&lt;br /&gt;            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(ofs &amp;gt;= 0 &amp;amp;&amp;amp; ofs &amp;lt;= metrics.GetSpace(i))&lt;br /&gt;                &lt;span style="color:blue;"&gt;return &lt;/span&gt;i;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color:blue;"&gt;return &lt;/span&gt;-1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public static int &lt;/span&gt;HitTestWithSizing(&lt;span style="color:blue;"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;metrics, &lt;span style="color:blue;"&gt;double &lt;/span&gt;v, &lt;span style="color:blue;"&gt;out bool &lt;/span&gt;overSizingGrip)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;for &lt;/span&gt;(&lt;span style="color:blue;"&gt;int &lt;/span&gt;i = 0; i &amp;lt; metrics.Count; i++)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:blue;"&gt;double &lt;/span&gt;ofs = v - metrics.GetStart(i);&lt;br /&gt;            &lt;span style="color:blue;"&gt;double &lt;/span&gt;space = metrics.GetSpace(i);&lt;br /&gt;            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(ofs.InNeighborhood(space, 3))&lt;br /&gt;            {&lt;br /&gt;                overSizingGrip = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;br /&gt;                &lt;span style="color:blue;"&gt;return &lt;/span&gt;i;&lt;br /&gt;            }&lt;br /&gt;            &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(ofs.InBetween(0, space, &lt;span style="color:#2b91af;"&gt;DoubleExtensions&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;EndpointInclusionMode&lt;/span&gt;.LeftInclusive))&lt;br /&gt;            {&lt;br /&gt;                overSizingGrip = &lt;span style="color:blue;"&gt;false&lt;/span&gt;;&lt;br /&gt;                &lt;span style="color:blue;"&gt;return &lt;/span&gt;i;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        overSizingGrip = &lt;span style="color:blue;"&gt;false&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color:blue;"&gt;return &lt;/span&gt;-1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;private delegate &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect CVR_GetRect&lt;/span&gt;();&lt;br /&gt;    &lt;span style="color:blue;"&gt;private delegate void &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CVR_UpdateRect&lt;/span&gt;(&lt;span style="color:blue;"&gt;double &lt;/span&gt;space);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;public static void &lt;/span&gt;ComputeVisibleRange(&lt;span style="color:blue;"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDimensionMetrics &lt;/span&gt;metrics, &lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;visibleRect, &lt;span style="color:#2b91af;"&gt;Direction &lt;/span&gt;direction, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;first, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;second)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;if&lt;/span&gt;(direction != &lt;span style="color:#2b91af;"&gt;Direction&lt;/span&gt;.Horizontal &amp;amp;&amp;amp; direction != &lt;span style="color:#2b91af;"&gt;Direction&lt;/span&gt;.Vertical)&lt;br /&gt;            &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"direction must be horizontal (columns) or vertical (rows)"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"direction"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;int &lt;/span&gt;min = metrics.Count;&lt;br /&gt;        &lt;span style="color:blue;"&gt;int &lt;/span&gt;max = -1;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;var &lt;/span&gt;initializeRect = direction == &lt;span style="color:#2b91af;"&gt;Direction&lt;/span&gt;.Vertical ?&lt;br /&gt;            (&lt;span style="color:#2b91af;"&gt;CVR_GetRect&lt;/span&gt;)(() =&amp;gt; &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(visibleRect.Left, 0, visibleRect.Width, 0))&lt;br /&gt;            : (&lt;span style="color:#2b91af;"&gt;CVR_GetRect&lt;/span&gt;)(() =&amp;gt; &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Rect&lt;/span&gt;(0, visibleRect.Top, 0, visibleRect.Height));&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#2b91af;"&gt;Rect &lt;/span&gt;rngRect = initializeRect();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;var &lt;/span&gt;updateRectSize = direction == &lt;span style="color:#2b91af;"&gt;Direction&lt;/span&gt;.Vertical ?&lt;br /&gt;            (&lt;span style="color:#2b91af;"&gt;CVR_UpdateRect&lt;/span&gt;)((&lt;span style="color:blue;"&gt;double &lt;/span&gt;space) =&amp;gt; rngRect.Height = space)&lt;br /&gt;            : (&lt;span style="color:#2b91af;"&gt;CVR_UpdateRect&lt;/span&gt;)((&lt;span style="color:blue;"&gt;double &lt;/span&gt;space) =&amp;gt; rngRect.Width = space);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;var &lt;/span&gt;updateRectPos = direction == &lt;span style="color:#2b91af;"&gt;Direction&lt;/span&gt;.Vertical ?&lt;br /&gt;            (&lt;span style="color:#2b91af;"&gt;CVR_UpdateRect&lt;/span&gt;)((&lt;span style="color:blue;"&gt;double &lt;/span&gt;space) =&amp;gt; rngRect.Y += space)&lt;br /&gt;            : (&lt;span style="color:#2b91af;"&gt;CVR_UpdateRect&lt;/span&gt;)((&lt;span style="color:blue;"&gt;double &lt;/span&gt;space) =&amp;gt; rngRect.X += space);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;for &lt;/span&gt;(&lt;span style="color:blue;"&gt;int &lt;/span&gt;i = 0; i &amp;lt; metrics.Count; i++)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:blue;"&gt;double &lt;/span&gt;space = metrics.GetSpace(i);&lt;br /&gt;            updateRectSize(space);&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(rngRect.IntersectsWith(visibleRect))&lt;br /&gt;            {&lt;br /&gt;                min = &lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Min(i, min);&lt;br /&gt;                max = &lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Max(i, max);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            updateRectPos(space);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        first = min;&lt;br /&gt;        second = max;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;In IDimensionMetrics, GetStart gives the starting position of a row or column, and GetSpace gives the space that it occupies.  The extension method GetEnd returns the result of GetStart + GetSpace for a given column.  TotalSpace is the sum of all GetSpace values for all rows/columns in the IDimensionMetrics.  It could have also been computed as an extension method, but I decided it would be better as a property so that the IDimensionMetrics implementer could precompute it.&lt;/p&gt;&lt;p&gt;The HitTestNoSizing and HitTestWithSizing extension methods help determine which column or row a given point is over (for mouse hit testing).  The former ignores sizing grips, while the latter will indicate the proper position for a sizing grip (currently hardcoded to a neighborhood of 3 device-independent pixels on each side of the sizing line).&lt;/p&gt;&lt;h3&gt;Selection Info&lt;/h3&gt;&lt;p&gt;First of all, my grid only supports selection of rows / columns / cells in the scrolling area of the grid.  For that reason, I have a single SelectionInfo binding for all regions, and the columns / rows used by the SelectionInfo members (FirstCol, FirstRow, LastCol, LastRow, etc.) are relative to the top left corner of the data region (HVScrollRegion).  If I needed support for selecting within the fixed rows and columns, then there would be some additional complexity in my code but it could be supported.  I think of the fixed rows and fixed columns as essentially being 'extended' headers, so it doesn't make sense to select them, or have an active cell in these regions (just as it doesn't make sense to be able to make the active cell be the 'C' header in the C column of Excel!).&lt;/p&gt;&lt;p&gt;As with my other stuff, selection info has an interface that exposes the functionality required by the system - ISelectionInfo, defined as follows.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;SelectionType&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    None,&lt;br /&gt;    Rows,&lt;br /&gt;    Columns,&lt;br /&gt;    Cells,&lt;br /&gt;    All,&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ISelectionInfo&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;SelectionType &lt;/span&gt;SelectionType { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;FirstRow { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;FirstCol { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;LastRow { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;LastCol { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;AnchorRow { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;AnchorCol { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;ActiveRow { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;ActiveCol { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SelectColumn(&lt;span style="color:blue;"&gt;int &lt;/span&gt;column, &lt;span style="color:blue;"&gt;bool &lt;/span&gt;extend);&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SelectRow(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;bool &lt;/span&gt;extend);&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SelectCell(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;int &lt;/span&gt;column, &lt;span style="color:blue;"&gt;bool &lt;/span&gt;extend);&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SelectAll();&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;Clear();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;MaxRow { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;MaxCol { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;event &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;EventHandler &lt;/span&gt;SelectionChanged;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;I'm still not sure whether this interface will remain the same forever, I might change it to act more like Excel (i.e. removing the distinction of SelectionType and just making the different selection rendering be handled by comparing FirstRow/FirstCol with 0, and LastRow/LastCol with MaxRow/MaxCol).  The interface is pretty self-explanatory, except for AnchorXXX and ActiveXXX.  ActiveXXX is used to track where the keyboard has you on a keyboard-based selection extension (i.e. you hold shift and move around with the keyboard).  AnchorXXX is used to track the starting cell for the selection.  When moving away from a selection (without the shift key held), AnchorXXX is the position from which you start.  This is counterintuitive to me, but it's how Excel works so I've replicated it.&lt;/p&gt;&lt;p&gt;Notice that ISelectionInfo is just the 'keeper' of the selection, and provides some methods for modifying the selection, but it doesn't have anything to do with the keyboard or the mouse.  The support for modifying the selection via keyboard or mouse is isolated in the KeyboardManager and MouseManager classes, discussed in a later post from this series.&lt;/p&gt;&lt;h3&gt;Render Info&lt;/h3&gt;&lt;p&gt;Within each of the regions, we need to be able to obtain and change the cell text, get the render flags (i.e. is it selected, is it a special cell, etc.), get the text alignment, and some other special info for the grid region.  The interfaces involved are IRenderInfo and IButtonInfo.  The applicable definitions are as follows.&lt;/p&gt;&lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;Flags&lt;/span&gt;]&lt;br /&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CellRenderFlags&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    None = 0,&lt;br /&gt;    TopLeft = 1,&lt;br /&gt;    ColHeader = 2,&lt;br /&gt;    RowHeader = 4,&lt;br /&gt;    FixedCol = 8,&lt;br /&gt;    FixedRow = 16,&lt;br /&gt;    Active = 32,&lt;br /&gt;    Selected = 64,&lt;br /&gt;    Hover = 128,&lt;br /&gt;    Anchor = 256,&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;static class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CellRenderFlagsExtensions&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;public static bool &lt;/span&gt;Contains(&lt;span style="color:blue;"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CellRenderFlags &lt;/span&gt;target, &lt;span style="color:#2b91af;"&gt;CellRenderFlags &lt;/span&gt;flag)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:blue;"&gt;return &lt;/span&gt;(target &amp;amp; flag) == flag;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IRegionRenderInfo&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color:green;"&gt;    &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CellRenderFlags &lt;/span&gt;GetCellFlags(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;int &lt;/span&gt;col);&lt;br /&gt;    &lt;span style="color:blue;"&gt;string &lt;/span&gt;GetCellText(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;int &lt;/span&gt;col);&lt;br /&gt;    &lt;span style="color:blue;"&gt;void &lt;/span&gt;SetCellText(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;int &lt;/span&gt;col, &lt;span style="color:blue;"&gt;string &lt;/span&gt;text);&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;TextAlignment &lt;/span&gt;GetTextAlignment(&lt;span style="color:blue;"&gt;int &lt;/span&gt;row, &lt;span style="color:blue;"&gt;int &lt;/span&gt;col);&lt;br /&gt;   &lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;Orientation &lt;/span&gt;ButtonOrientation { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:#2b91af;"&gt;IButtonInfo &lt;/span&gt;GetButtonInfo(&lt;span style="color:blue;"&gt;int &lt;/span&gt;index);&lt;br /&gt;    &lt;span style="color:blue;"&gt;int &lt;/span&gt;ButtonCount { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;event &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;EventHandler &lt;/span&gt;ResetRenderInfo;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IButtonInfo&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    ... &amp;lt;removed for brevity&amp;gt; ...&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;We will ignore IButtonInfo and the associated bits from the IRenderInfo interface for now and focus on the other IRenderInfo information.  The cell render flags are various pieces of info that allow the CellRenderer class (discussed in a later post) to do its work.  The CellRenderer also needs to know the text alignment for the cell and the cell text itself.  The SetCellText method is provided for the in-place editor that allows modification of the cell text.&lt;/p&gt;&lt;p&gt;This concludes our discussion of the data binding interfaces used by the grid.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-2982990669662406993?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/2982990669662406993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=2982990669662406993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2982990669662406993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2982990669662406993'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/08/building-wpf-grid-control-part-1-of.html' title='Building a WPF Grid Control (Part 1 of ?)'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/kelly.p.leahy/SJNwQtHUAuI/AAAAAAAAABM/P8NMwa_Dphg/s72-c/image_thumb%5B4%5D.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4931885948119271056</id><published>2008-06-12T11:24:00.001-07:00</published><updated>2008-06-12T11:25:42.269-07:00</updated><title type='text'>MSDN Articles Online (.chm)</title><content type='html'>&lt;p&gt;Glenn Block (@gblock on Twitter) just posted an tweet that mentioned the existence of these.&amp;#160; I had no idea they were there and I'm sure others didn't as well - so here you go: &lt;a href="http://is.gd/vZE"&gt;http://is.gd/vZE&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Enjoy!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4931885948119271056?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4931885948119271056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4931885948119271056' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4931885948119271056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4931885948119271056'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/06/msdn-articles-online-chm.html' title='MSDN Articles Online (.chm)'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-885753601874356918</id><published>2008-06-08T00:16:00.001-07:00</published><updated>2008-06-08T00:20:32.964-07:00</updated><title type='text'>Extension Methods are way cool!</title><content type='html'>&lt;p&gt;OK.&amp;#160; So everyone's heard of LINQ by now.&amp;#160; Most everyone has even heard of some of the cool features of C# 3.0 (lambdas), but in my mind, the coolest - extension methods - largely goes unnoticed.&amp;#160; Extension methods are the plumbing on which LINQ and some of the other cool features in the C# 3.0 libraries are implemented.&amp;#160; They are, in my opinion, the best feature C# has introduced since Generics, and are possibly one of the best features added to traditional languages EVER!&lt;/p&gt;&lt;p&gt;Consider the following - you have a class that someone else wrote.&amp;#160; On their class, they've provided a public interface for doing all of the things you need, but there are several additional things that you've implemented (as a separate utility set of functions) that it would be nice to add to the class' public interface.&amp;#160; Unfortunately, the class is marked 'sealed', or it is the base of a large hierarchy of classes that you simply can't add your functionality to (since you can't cause classes in a vendors library to derive from your 'new' version of their base class).&lt;/p&gt;&lt;p&gt;Extension methods to the rescue - all you need to do is declare a static class in your library (which you probably already have called 'StringUtils' or something like that :)), and provide some static methods on it that use the new 'this' keyword on their first argument.&amp;#160; Magically, the compiler will then 'add' this method to all items that have a type that is compatible with the type you have in the 'this-marked' argument.&lt;/p&gt;&lt;p&gt;For example:&lt;/p&gt;&lt;pre&gt;public static class StringUtils&lt;br /&gt;{&lt;br /&gt;    public static string RemoveAll(this string s, params string[] args)&lt;br /&gt;    {&lt;br /&gt;        string ret = s;&lt;br /&gt;        foreach(string sremove in args)&lt;br /&gt;            ret = ret.Replace(sremove, string.Empty);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;by the way, of course I know this is the most horrible way to implement this function - it's just an example so don't tell me how crappy my code is or that I should be using StringBuilder or yada yada yada...!&lt;/p&gt;&lt;p&gt;The point of this is that after declaring such a function, all objects of type 'string' syntactically receive a member called 'RemoveAll' that has a single 'params' argument.&amp;#160; This is VERY cool.&lt;/p&gt;&lt;p&gt;The coolest thing about this - you can also do it for interfaces, enums, and various other types that you can't possibly provide &amp;quot;code&amp;quot; for in a more traditional way.&lt;/p&gt;&lt;h4&gt;What else?&lt;/h4&gt;&lt;p&gt;Much of the code that I write on a day-to-day basis works with tree-based data structures.&amp;#160; Some of these structures can get very complicated and much of my unit test code needs to do asserts over a large part of a tree (after performing some complex operation).&amp;#160; As a for instance, consider an expression parser.&amp;#160; Such a parser would presumably build an AST for the expression it's given and return that AST for further processing.&amp;#160; ASTs for all but the most simple expressions can get very tedious to 'check' for validity when writing a parser.&lt;/p&gt;&lt;p&gt;I've recently begun using extension methods for by base node class to help with my unit testing.&amp;#160; I directly put the unit test 'asserts' into the extension methods, and these extension methods are in NO WAY suitable to exist in the library that is being tested (why on earth would I want to have all this extra junk in my library just to support unit tests).&amp;#160; As a matter of fact, my libraries even target .NET 3.0 (C# 2.0) rather than .NET 3.5, C# 3.0.&amp;#160; However, that doesn't stop me from being able to use extension methods in my unit testing code (which doesn't get deployed to my clients, so I don't require them to have 3.5, I just have to have it on my dev machine and build machine).&lt;/p&gt;&lt;p&gt;Here's a simple example of how some of my unit testing code looks:&lt;/p&gt;&lt;pre&gt;[Test]&lt;br /&gt;public void FormulaTests2()&lt;br /&gt;{&lt;br /&gt;    PrimaryLexer l = new PrimaryLexer();&lt;br /&gt;    StringReaderAdapter sra = new StringReaderAdapter(&amp;quot;a / (b + c)&amp;quot;, 0);&lt;br /&gt;    InforceScriptLexerFilter lf = new InforceScriptLexerFilter(sra, l);&lt;br /&gt;    InforceScriptSemanticParser sp = new InforceScriptSemanticParser(lf);&lt;br /&gt;&lt;br /&gt;    RootFormula rf = sp.Parse();&lt;br /&gt;&lt;br /&gt;    // look for 'a' and '/'&lt;br /&gt;    rf.Body.Is&amp;lt;binaryop&amp;gt;()&lt;br /&gt;        .OperatorIs(InforceScriptTokenId.Slash)&lt;br /&gt;            .Left.Is&amp;lt;invokeop&amp;gt;()&lt;br /&gt;                .IdRef.Is&amp;lt;idreference&amp;gt;()&lt;br /&gt;                    .NameIs(&amp;quot;a&amp;quot;);&lt;br /&gt;    // look for 'b' and '+'&lt;br /&gt;    rf.Body.Is&amp;lt;binaryop&amp;gt;()&lt;br /&gt;        .Right.Is&amp;lt;binaryop&amp;gt;()&lt;br /&gt;            .OperatorIs(InforceScriptTokenId.Plus)&lt;br /&gt;                .Left.Is&amp;lt;invokeop&amp;gt;()&lt;br /&gt;                    .IdRef.Is&amp;lt;idreference&amp;gt;()&lt;br /&gt;                        .NameIs(&amp;quot;b&amp;quot;);&lt;br /&gt;    // look for 'c'&lt;br /&gt;    rf.Body.Is&amp;lt;binaryop&amp;gt;()&lt;br /&gt;        .Right.Is&amp;lt;binaryop&amp;gt;()&lt;br /&gt;            .Right.Is&amp;lt;invokeop&amp;gt;()&lt;br /&gt;                .IdRef.Is&amp;lt;idreference&amp;gt;()&lt;br /&gt;                    .NameIs(&amp;quot;c&amp;quot;);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;In order to make all this possible, I defined a few extension methods:&lt;/p&gt;&lt;pre&gt;internal static class TreeAssertions&lt;br /&gt;{&lt;br /&gt;    public static T Is&amp;lt;T&amp;gt;(this ExpressionBase node) where T : ExpressionBase&lt;br /&gt;    {&lt;br /&gt;        Assert.IsInstanceOfType(typeof(T), node, &amp;quot;wrong node type&amp;quot;);&lt;br /&gt;        return (T)node;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static IdReference NameIs(this IdReference node, string name)&lt;br /&gt;    {&lt;br /&gt;        Assert.AreEqual(name, node.Id.Name, &amp;quot;names don't match&amp;quot;);&lt;br /&gt;        return node;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static BinaryOp OperatorIs(this BinaryOp node, InforceScriptTokenId op)&lt;br /&gt;    {&lt;br /&gt;        Assert.AreEqual(op, node.OperatorTokenId);&lt;br /&gt;        return node;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;As you can see, the 'Is' test checks the type of a node, and then returns the node, so I can continue checking other things for the same node (assuming it 'passed' the check).&amp;#160; The same is true for the 'NameIs' and 'OperatorIs' checks.&amp;#160; This sort of programming is generally referred to (I think) as 'Literate Programming' - a technique for which the venerable D. Knuth is given the credit.&amp;#160; However, in order to do this sort of thing in the past, I'd have needed to put all these methods on my base class for the tree nodes, something that would have absolutely been the 'wrong' thing to do (since this test code should not be part of the library-proper).&amp;#160; (By the way, I think this style is now being referred to as 'fluent interfaces' in programming circles).&lt;/p&gt;&lt;p&gt;I can't wait to see what else I can find to use these methods for.&amp;#160; I've already found it to be an amazing benefit to my productivity and the readability of my tests.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-885753601874356918?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/885753601874356918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=885753601874356918' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/885753601874356918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/885753601874356918'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/06/extension-methods-are-way-cool.html' title='Extension Methods are way cool!'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1471580798045793701</id><published>2008-06-05T21:00:00.001-07:00</published><updated>2008-06-05T21:00:09.944-07:00</updated><title type='text'>CI / TeamCity is Seriously COOL!</title><content type='html'>&lt;p&gt;OK... I'll be the first to admit that I'm just getting into Agile processes and I'm still a bit skeptical.&amp;#160; At first, I thought (CI = Continuous Integration) 'CI builds - is it really worthwhile?'.&amp;#160; Now, I've got a &lt;a href="http://www.jetbrains.com/teamcity/" target="_blank"&gt;TeamCity&lt;/a&gt; site &amp;amp; build agent up and going, and I'm totally SOLD!&lt;/p&gt;  &lt;p&gt;Here are the benefits as I see them for our situation:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;We know almost immediately when someone broke the build (they know too!)&lt;/li&gt;    &lt;li&gt;We have better checkin quality now that people are tired of getting those 'compilation failed' emails.&lt;/li&gt;    &lt;li&gt;We always have a source to go to for a 'current' build - no need to get the sources and build on your own machine, or go ask a 'build master' to get you a build.&lt;/li&gt;    &lt;li&gt;We have other 'automation' points that we can hook into when we're ready to move on to bigger &amp;amp; better methods.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;As an example of #4, I hope to soon have our NUnit tests running as part of an automated build.&amp;#160; I also think we can have automated installer builds going if we wanted to.&amp;#160; And, best of all, by virtue of TeamCity's ability to 'watch' our source control server for updates, and it's ability to run any arbitrary command line, NAnt, or MSBuild (or many more) task in response to those updates, the sky is the limit!&lt;/p&gt;  &lt;p&gt;I can't wait to get more 'good stuff' implemented on TeamCity.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1471580798045793701?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1471580798045793701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1471580798045793701' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1471580798045793701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1471580798045793701'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/06/ci-teamcity-is-seriously-cool.html' title='CI / TeamCity is Seriously COOL!'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7212611105076537457</id><published>2008-06-04T00:49:00.001-07:00</published><updated>2008-06-04T00:49:09.784-07:00</updated><title type='text'>The Day of Bugs</title><content type='html'>&lt;p&gt;Ok, I can honestly say that today was one of the weirder days that I've had in a long while.&amp;#160; I don't know about others, but I can say with confidence that I've never personally identified a bug in Visual Studio in my career.&amp;#160; I've seen plenty of them mentioned by other folks, I've seen 'features' that I'd be inclined to call a bug (but could be interpreted either way), but I've never really found a bug myself.&lt;/p&gt;  &lt;p&gt;Today, I found two.&amp;#160; I guess it's a case of 'when it rains, it pours'.&amp;#160; One of them was known long before I 'found' it, but obviously not known to me.&amp;#160; The other, I'm pretty confident, is still unknown to 'everyone'.&lt;/p&gt;  &lt;h1&gt;Bug #1 - Dynamic Version vs. BAML.&lt;/h1&gt;  &lt;p&gt;Ok...&amp;#160; So we've done a fair bit of playing with WPF on my project, and we've done some custom control development (user controls) in WPF for use in our application.&amp;#160; WPF is very convenient for being able to prototype and design the UX/UI of something without being bogged down by all the crap you have to do to customize WinForms (our users seem to never like the 'way it is').&amp;#160; I can say that I feel pretty comfortable that my skills with WPF, while not the best on the block, are probably up there along with most of the folks currently doing WPF development.&amp;#160; I've done a ton of data binding work, and feel pretty confident that I know most of the tricks there - especially thanks to the wonderful work of &lt;a href="http://www.beacosta.com/blog/" target="_blank"&gt;Bea Costa&lt;/a&gt;!&lt;/p&gt;  &lt;p&gt;So, I was very puzzled when one of our developers started having issues with running our application's forms that use one of my user controls.&amp;#160; The user control was pretty simple - it was a list of names that had alternating highlights for the rows (one row was white, one was gray, etc.).&amp;#160; It did a few other things, but mostly that was the gist of it.&amp;#160; This is one of the simpler controls we have.&amp;#160; Anyway, the weird thing was that the 'bug' that we kept seeing only appeared when running the debug build of our application, and it only appeared when our UI was being used from the APL application.&amp;#160; It never appeared in release builds, and it never appeared when running debug mode in our UI test harness.&lt;/p&gt;  &lt;p&gt;So, naturally, I looked first at the APL runtime, thinking it was a bad install on this dev's machine.&amp;#160; We then took his build and his APL workspace and ran it on my machine.&amp;#160; To my surprise, it crashed on my machine too.&amp;#160; Then, we tried running one of my builds on his machine - it worked (also to my surprise!).&amp;#160; So then, I concluded it was a problem with his machine.&lt;/p&gt;  &lt;p&gt;Two days later, after he had gotten some other work done and managed to uninstall all of .NET 2.0 through 3.5, VS2005 and VS2008, and then reinstall all of them (carefully in order), he tried it again.&amp;#160; BOOM!&amp;#160; It still didn't work.&amp;#160; I brought him my old laptop, and I had IT set it up for him to be able to use it instead of his desktop, thinking we'd be rebuilding his desktop from scratch.&amp;#160; All the while, still being puzzled by the fact that the behavior ran around to different machines and environments and was so skittish.&lt;/p&gt;  &lt;p&gt;Later that day, he came over to my desk and told me the problem started appearing on his release builds too.&amp;#160; I thought, &amp;quot;oh great - a viral bug!&amp;quot;.&amp;#160; He then said that the problem also started appearing on my builds.&amp;#160; At this point, I thought - &amp;quot;ok, there's gotta be something else going on here&amp;quot;.&lt;/p&gt;  &lt;p&gt;The bad part about this bug was this - whenever you ran the application, it would look like it wanted to pop up an error dialog, in fact it would show the thread exception dialog (&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.threadexceptiondialog.aspx" target="_blank"&gt;System.Windows.Forms.ThreadExceptionDialog&lt;/a&gt;) briefly (actually several of them on top of each other), but then the application would disappear before you could do anything.&amp;#160; Apparently, looking back, the problem was on one of WPF's &amp;quot;special&amp;quot; threads and APL apparently doesn't react very nicely to the .NET AppDomain having threads other than the main UI thread throw exceptions.&lt;/p&gt;  &lt;p&gt;Finally recognizing that I might be able to do something about this, I went into the code and added an exception handler with a plain-old message box in it (e.ToString()).&amp;#160; Looking at the exception text, I saw that it said something about a XAML parse error and that my ValueConverter couldn't be loaded (I had a ValueConverter as a static resource in my XAML for getting the backcolor brush for doing the highlighting).&amp;#160; This error message pointed me to: &lt;a href="http://rrelyea.spaces.live.com/blog/cns!167AD7A5AB58D5FE!497.entry" target="_blank"&gt;Rob Relyea's blog post&lt;/a&gt; (along with several MSDN forums posts).&amp;#160; The only thing was that his post didn't apply completely to my issue.&amp;#160; But, the workarounds did.&amp;#160; It turned out that I was using AssemblyVersion(1.0.*) in my files (which I really like for our 'in dev' work), but it was causing problems.&amp;#160; It seems that the reason the bug was so 'fleeting' was that there must have been a timing issue on the fourth bit of the version number (the revision), since it's based on a timestamp.&lt;/p&gt;  &lt;p&gt;Apparently, my computer is too fast (most of the time), so I didn't see this bug on my builds, just on my colleagues'!&amp;#160; As I said, this bug has been known about for a long time, and while I'm not thrilled with the workaround, it's there and working, so I'll live with it.&lt;/p&gt;  &lt;p&gt;BTW, I spent nearly 4 days chasing this bug, off and on (my colleague did most of the legwork).&amp;#160; It wasn't much fun, being that we couldn't get an error message for the first 3 of those.&lt;/p&gt;  &lt;h1&gt;Bug #2 - VS2008 STL vs. NUnit, C++/CLI, and ME!&lt;/h1&gt;  &lt;p&gt;So, I spent the last 4 days chasing what I though &lt;em&gt;&lt;strong&gt;must&lt;/strong&gt;&lt;/em&gt; have been a bug in our code, only to figure out that I'm pretty sure it's a bug in MS's STL implementation (for Debug builds).&amp;#160; However, this bug is really hard to find (though it, at least, is VERY consistent - i.e. happens every time and is very reproducible).&lt;/p&gt;  &lt;p&gt;First, some background on our design.&amp;#160; Our application consists of two major pieces, a UI, and a backend calculation engine.&amp;#160; The UI is written in .NET 3.0/3.5 (C#), and the backend is written in C++ (native).&amp;#160; However, these systems need to be able to share a common file format.&amp;#160; To meet this need, we developed a generic file library in native C++ code that can be used to read/write files for our system.&amp;#160; The files are basically like MS's structured storage, but with the features and interfaces that we desired for our system (along with a design oriented towards meeting our required performance characteristics).&lt;/p&gt;  &lt;p&gt;All of our file structures are build upon this file library, along with several other native libraries that support it and some of the other 'shared' features.&amp;#160; We also have a generic 'key' library (this is a domain concept for us - you can think of it as a property bag with some special 'matching' features).&lt;/p&gt;  &lt;p&gt;In order to support using these libraries from both C++ and C# code, we decided we'd write the implementations in native C++ using traditional object-oriented design principles (many of which were lifted from my C#/Java experiences), and then write a thin C++/CLI (the managed C++ language) wrapper around this library using the IJW (it just works) interop supported by C++/CLI.&amp;#160; Then, our C# clients would call into the C++/CLI managed library (not even knowing that it's implemented in C++) just as they would call into managed C# code, but be able to use the underlying data structures and implementation of the native libraries.&amp;#160; I think this design is pretty elegant, and we solved quite a few interesting issues when developing it.&amp;#160; We've been using it now for some time and it's working quite well.&lt;/p&gt;  &lt;p&gt;So...&amp;#160; now, the bug.&amp;#160; Just recently we needed to add a new feature to the 'key' library.&amp;#160; This library is very simple and the feature was also quite simple.&amp;#160; I added it to the native code, added it in the managed C++/CLI library, and added the C# unit test code to exercise it.&amp;#160; By convention, we only run our unit tests in Release mode, unless we're debugging them, since we only want to take the time to test in one build environment and it makes most sense to test the bits that are going out the door...&lt;/p&gt;  &lt;p&gt;Anyway, so I tested in release mode, the tests all passed, and I checked in.&amp;#160; I was happy and I went home for the day.&amp;#160; The next day, I happened to be compiling in Debug mode and I decided to run what I was working on.&amp;#160; I had forgotten that my startup project in VS2008 was set to the unit tests for the 'key' library, so the unit tests ran instead of what I was intending to test.&amp;#160; To my surprise, the unit tests for the 'key' library 'exploded' (they didn't fail, they caused an AccessViolationException that was caught by VS2008 and popped up in the debugger!).&amp;#160; The AV was showing up on the destructor call for one of our unmanaged C++ objects (native library).&lt;/p&gt;  &lt;p&gt;To make matters worse, the bug only showed up when the finalizer was called for the class, and even weirder, only showed up when the variables were not deterministically destroyed (i.e. using IDispose and 'using').&amp;#160; Since my unit test code wasn't using 'using' anywhere, I saw the 'explosion'.&amp;#160; But, I saw it only when the finalizer was called (much later than the offending code, obviously).&amp;#160; I invested some time writing code to track which object was the culprit, and after figuring out which (using 'value numbering', a technique I use a lot in single-threaded debugging of applications with lots of object instances and no unique identifiers in them), I followed the code.&amp;#160; It was not at all obvious why there was a problem.&amp;#160; In fact, I looked at it for several days and couldn't figure out what the problem was.&lt;/p&gt;  &lt;p&gt;I then posted &lt;a href="http://forums.msdn.microsoft.com/en-US/vclanguage/thread/f2f69a47-1a19-4116-8759-9e6b08443ab7" target="_blank"&gt;here&lt;/a&gt;, and called my Arch. Evangelist at MS and talked with him about it, and still couldn't figure out what it is (the spoiler is the last post in the thread).&amp;#160; I finally had to resort to the 'commenting' technique to track down the bug.&amp;#160; I first commented out all unit tests and started adding them back in one by one.&amp;#160; Once I found which unit test failed, I commented out the entire test and started adding code back in block by block.&amp;#160; Once I found the offending block, I looked down into the C++ code and &lt;strong&gt;&lt;em&gt;STILL &lt;/em&gt;&lt;/strong&gt;couldn't find anything wrong with it.&lt;/p&gt;  &lt;p&gt;At that point, I decided I needed to think outside the box.&amp;#160; I looked at what was different between the various method calls that worked and didn't work, and decided that the throwing of the exception might be a problem.&amp;#160; First, I removed all the code in the offending method.&amp;#160; Now, my test failed, but it didn't explode.&amp;#160; So, I put the code back, and looked at the exception more thoroughly - I decided to move it to the head of the function.&amp;#160; That also caused my test to fail, but it didn't explode.&amp;#160; So then I concentrated on the code before the exception (in the original function).&amp;#160; I kept saying to myself - there's NOTHING wrong with this code!&amp;#160; (you can see the code in the &lt;a href="http://forums.msdn.microsoft.com/en-US/vclanguage/thread/f2f69a47-1a19-4116-8759-9e6b08443ab7" target="_blank"&gt;MSDN post&lt;/a&gt;).&amp;#160; Finally, I thought - &amp;quot;it &lt;em&gt;&lt;strong&gt;has&lt;/strong&gt;&lt;/em&gt; to be this code, so let's assume it's broken and figure out when and why&amp;quot;.&amp;#160; I then restructured the code (as described in the MSDN post) and determined that it was absolutely something in the 'begin()' or 'end()' STL vector calls.&amp;#160; There's no way I messed that up - that's &lt;strong&gt;&lt;em&gt;their&lt;/em&gt;&lt;/strong&gt; code.&amp;#160; Voil&amp;#224; - bug #2.&lt;/p&gt;  &lt;p&gt;For this one, I'm going to have to figure out how to submit it to MS.&amp;#160; I'm sure nobody's seen this one (at least as far as I can tell from &lt;a href="http://www.google.com/search?hl=en&amp;amp;q=VC2008+bug+C%2B%2B+STL+vector+empty+access+violation+debug&amp;amp;btnG=Google+Search" target="_blank"&gt;searching&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Whew!&amp;#160; Looking forward (hopefully) to not having very many more of those days!&lt;/strong&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7212611105076537457?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7212611105076537457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7212611105076537457' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7212611105076537457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7212611105076537457'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/06/day-of-bugs.html' title='The Day of Bugs'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1614174027452726910</id><published>2008-05-31T00:11:00.001-07:00</published><updated>2008-05-31T00:11:05.371-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VC++ Runtime'/><title type='text'>Redistributing C++ runtime components</title><content type='html'>&lt;p&gt;Ok.&amp;#160; I've had to look for this several times over the years.&amp;#160; This time, I finally decided to just post it on my blog so I can find it again later :)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/vcblog/archive/2007/10/12/how-to-redistribute-the-visual-c-libraries-with-your-application.aspx" target="_blank"&gt;Here it is&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Hopefully it helps you sometime too...&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1614174027452726910?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1614174027452726910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1614174027452726910' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1614174027452726910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1614174027452726910'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/05/redistributing-c-runtime-components.html' title='Redistributing C++ runtime components'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-8987514405406088669</id><published>2008-05-29T20:30:00.000-07:00</published><updated>2008-05-29T20:33:33.700-07:00</updated><title type='text'>StL gave Oakwood 1/2 Million Dollars???</title><content type='html'>What the hell?&lt;br /&gt;&lt;br /&gt;Article in recent STL Business Journal:&lt;br /&gt;&lt;br /&gt;"St. Louis development fund invests in Oakwood Systems.Oakwood Systems Group Inc. received a $500,000 investment for expansion from the St. L Business Development Fund, which invests in St. L based companies that are unable to access sufficient senior debt to finance organic growth or acquisition.Creve Coeur MO based technology consulting firm Oakwood Systems is one of the fastest growing private companies in the St. Louis area, according to Business Journal research.  The company reported $7.5 million in fiscal 2006 revenue, a 92.3 percent increase from fiscal 2004 revenue of $3.9 million.  The firm has 85 employees and an office in Nashville, TN."&lt;br /&gt;&lt;br /&gt;If this isn't the funniest thing I've heard in a long time - it's gotta be up there.  Of course this will only be funny to those of you who have heard my stories about my time at Oakwood and the goings on there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-8987514405406088669?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/8987514405406088669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=8987514405406088669' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8987514405406088669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8987514405406088669'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/05/stl-gave-oakwood-12-million-dollars.html' title='StL gave Oakwood 1/2 Million Dollars???'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7785135468344125390</id><published>2008-05-26T23:25:00.000-07:00</published><updated>2008-05-27T00:01:16.466-07:00</updated><title type='text'>Patching from a single .exe</title><content type='html'>We've been doing some work lately to try to figure out a good way to make our software patches go out the door as a single .exe. We aren't using MSI for our patches because we need to be able to do some things that MSI can't do (i.e. install older patches over newer versions, verify the current system version before installing, always install files, regardless of whether they are have been modified by the user or not, etc.).&lt;br /&gt;&lt;br /&gt;So, I was thinking about different approaches. As I saw it, there were:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Package everything in a zip, require users to download the zip and extract it into a temp folder, and run a .exe inside the zip that does the patch. Then require the user to delete the folder on their own.&lt;/li&gt;&lt;li&gt;Build an .EXE that has resources in it for the files that were to be included in the patch - have the .exe extract these resources to disk in the proper locations and perform the other logic necessary.&lt;/li&gt;&lt;li&gt;Build a generic packaging process, package stub, and 'package runner' that can solve the problem as well as other similar problems should we ever want to package anything else as a single .EXE (besides patches).&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I didn't like (1) for the UX - I think it's pretty nasty UX-wise. I didn't like (2) because there are several problems - (a) the person who would be building the patches doesn't really work in VS, and I don't want them compiling the code. I also don't want to write code to 'package' the resources - it's a pain. (b) I already know one other case where we will need to package stuff into a single .exe for deployment that isn't the same as our patch process, so I'd have to build a similar project again - I hate duplicate code...&lt;/p&gt;&lt;p&gt;I decided to go down the path of (3). I knew from my Win32 days that the .EXE loader will be perfectly fine with an .EXE with 'junk' concatenated to the end of it. I've done this several times in the past - the PE format doesn't have any problem with 'extra' bits at the end of the file. So, I decided to go with the idea of a stub .EXE with a 'package' tacked on the end.&lt;/p&gt;&lt;p&gt;The next question was - what should my package support? I decided that for me a package would be two things - a list of files, and an entry assembly (that gets run by the package stub upon loading). The package would be a 'manifest' (an XML file that lists the package contents), along with a stream of bytes for the package data. For my needs, it was sufficient if all packages contained (1) a list of files, (2) an entry assembly, (3) an argument to pass to the entry assembly on running it, and (4) a list of assemblies upon which the entry assembly depended. The entry assembly would be loaded and executed by the package stub (.EXE) upon running the .EXE.&lt;/p&gt;&lt;p&gt;So, the file looks like:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;table style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid; BORDER-COLLAPSE: collapse; TEXT-ALIGN: center; border-spacing: 0px" bordercolor="black" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BACKGROUND: #7fefef"&gt;Stub .EXE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND: #9fcfcf"&gt;Package Data Bits&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND: #bcdfaf"&gt;Package Manifest&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="BACKGROUND: #bfbfbf"&gt;Package Trailer&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Where the data bits are GZip compressed streams of bits corresponding to the items listed in the manifest, and the Package Trailer is a 'header' (trailer actually) that is of fixed length and identifies this file as a valid package (i.e. has a identifying 'magic number') and contains offsets of the various items within the file (i.e. the location of the first byte of data bits, and the length of the manifest).&lt;/p&gt;&lt;p&gt;Since my support code for this functionality is in a class library (I called it 'Packaging'), the class library is embedded in the stub .exe as a resource.  The stub performs the following steps when it is run:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;load the resource "Packaging" and call Assembly.Load on the byte array.&lt;/li&gt;&lt;li&gt;set up a 'resolver' to resolve this assembly for the other assemblies that might be loaded by this package.&lt;/li&gt;&lt;li&gt;unpackage the dependencies of the entry assembly and load them as well&lt;/li&gt;&lt;li&gt;unpackage the entry assembly&lt;/li&gt;&lt;li&gt;look for a 'Package' class in the global namespace of the entry assembly, and cast it to an IPackage (defined in Packaging assembly)&lt;/li&gt;&lt;li&gt;call 'Execute' method on the IPackage from (5), passing an IPackageHost interface that provides functionality for reading the contents of the package and interacting with the stub.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;(2) is an event handler attached to the AppDomain.CurrentDomain.AssemblyResolve event.&lt;/p&gt;&lt;p&gt;The IPackageHost is an interface that allows the IPackage.Execute implementation to gain access to the entries (and bits) in the manifest.  This host interface is provided by the stub, but can also be implemented by other code in order to do testing, extract packages, run them separately, etc.  In fact, my Packaging library provides the implementation of IPackageHost via a PackageHost class that is used by the stub .EXE to provide the necessary support to the entry assembly's IPackage implementation.&lt;/p&gt;&lt;p&gt;If you want more details on how this all works, give me a call, or shoot me an email - I'll be happy to provide more details.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7785135468344125390?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7785135468344125390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7785135468344125390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7785135468344125390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7785135468344125390'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/05/patching-from-single-exe.html' title='Patching from a single .exe'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4172726558612385019</id><published>2008-05-24T23:34:00.001-07:00</published><updated>2008-05-24T23:36:41.490-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ALT.NET'/><title type='text'>Another great ALT.NET event!</title><content type='html'>Yet another great ALT.NET event today.  Thanks Glenn for the conversation in the car on the way there (and congrats / good luck on your new job on MEF), thanks Justin for the space, and thanks everyone else for the great conversations.&lt;br /&gt;&lt;br /&gt;Hopefully people are interested in coming to my place in July or early Aug for one.&lt;br /&gt;&lt;br /&gt;I'll try to be more diligent about blogging some of my recent dev work.  I think it's pretty interesting and I haven't found similar content elsewhere.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4172726558612385019?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4172726558612385019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4172726558612385019' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4172726558612385019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4172726558612385019'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/05/another-great-altnet-event.html' title='Another great ALT.NET event!'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-948117501355753287</id><published>2008-04-21T09:51:00.000-07:00</published><updated>2008-05-29T23:52:07.939-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open Spaces'/><category scheme='http://www.blogger.com/atom/ns#' term='ALT.NET'/><title type='text'>Coolest weekend ever.</title><content type='html'>Ok... the weather sucked - it was snowing here - but otherwise this weekend was awesome. I got to meet a lot of great people, and some real top minds in the field. Who did I meet? Among others - Brad Abrams (.NETfx team, coauthor of framework guidelines book), Jeremy Miller (the StructureMap guy), Glenn Block (P&amp;amp;P guy), Scott Hanselman (goes without introduction), Martin Fowler (the 'Refactoring' book guy), Charlie Poole (the NUnit guy) ... the list goes on (no offense please if I met you and didn't include you in this list).&lt;br /&gt;&lt;br /&gt;I had a wonderful lunch conversation with Brad for about 20-30 minutes over lunch. It's amazing to have someone like Brad come sit down next to you, introduce himself, and then share a one-on-one conversation with you. It'd be like Fisher Black coming and sitting down next to an actuary and introducing himself and asking about your work. It's very hard to not feel intimidated in such a situation, but not only was Brad not intimidating, but he's a really genuinely nice guy to talk to. Hopefully I'll have the luck of meeting him again and having more conversations. hehehe... maybe he'll ask me if I want a job someday :) I can dream, right?&lt;br /&gt;&lt;br /&gt;All in all, this is the best work-related event I've ever been to, and it's probably the best weekend of my working life thus far. I definitely consider the 30 minutes I spend with Brad to be the best 30 minutes of my career to this point.&lt;br /&gt;&lt;br /&gt;If you ever hear of an 'open spaces' event, I highly recommend you jump on the opportunity to attend. Also, if you ever want to go to ALT.NET events, hopefully I'll see you there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-948117501355753287?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/948117501355753287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=948117501355753287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/948117501355753287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/948117501355753287'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/04/coolest-weekend-ever.html' title='Coolest weekend ever.'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-3122649170556223446</id><published>2008-03-20T16:54:00.000-07:00</published><updated>2008-03-20T16:55:12.000-07:00</updated><title type='text'>SSCLI code browser</title><content type='html'>Ok... This is pretty cool!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://labs.developerfusion.co.uk/SourceViewer/view/SSCLI/"&gt;http://labs.developerfusion.co.uk/SourceViewer/view/SSCLI/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-3122649170556223446?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/3122649170556223446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=3122649170556223446' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/3122649170556223446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/3122649170556223446'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/03/sscli-code-browser.html' title='SSCLI code browser'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-8147211776564792629</id><published>2008-02-25T10:54:00.000-08:00</published><updated>2008-02-25T11:09:26.386-08:00</updated><title type='text'>Interop, Interop, and more Interop</title><content type='html'>Well, we're sure doing our fair share of WinForms and WPF interop!  We've really jumped on the WPF bandwagon, but we really like the functionality of our application and aren't willing to give up major parts of it in order to go 'all' WPF.&lt;br /&gt;&lt;br /&gt;For instance, our Syntax Editor control (from &lt;a href="http://www.actiprosoftware.com/"&gt;http://www.actiprosoftware.com&lt;/a&gt;) is only available currently as a WinForms control.  Also, my management really likes the Infragistics Grid's functionality that we're using for our selection grid in our formula browser tab.  In addition, we really like our tabbed MDI style of windowing, and our tool windows (pinnable tool windows like in VS2005).&lt;br /&gt;&lt;br /&gt;Unfortunately, there are several ways in which WinForms doesn't play nice with WPF.  Basically, the problem is that when WinForms draws on a window, it 'owns' that space on the screen.  However, when WPF draws on a window, it is using DirectX compositing.  This makes lots of things in WPF very nice, but in order to allow WinForms controls to 'live' on a WPF window, they must have total control over the space where they 'live'.  This means that the WPF controls can not render 'on top of' the WinForms control.  This is very well documented behavior and basically the only way the WPF team could figure out to make this work (as far as I can tell).&lt;br /&gt;&lt;br /&gt;What does it mean for us?  A whole lot of interop.  Basically, we want to use WPF everywhere we can and would love to be able to use it for our whole application.  Currently, we can't use it for the whole app, and so we must use it where we can and hope for the best later.  However, tool windows have this neat 'auto-hide' feature with them.  We really liked the WPF 'SandDock' tab &amp;amp; dock controls from DivElements.  However, since our WinForms grid is in the main client area of our form layout, we couldn't use a WPF docking control, since when you drug the dockable windows around, or when they tried to 'flyout' from their 'auto-hide' position, they would do so UNDER the WinForms control!  That sucks, but it's the only way it can reasonably work.&lt;br /&gt;&lt;br /&gt;What's that mean?  Our docking controls can only be WinForms controls until we get rid of all the WinForms controls that a flyout would want to fly over (and replace them with WPF equivalents).  Now, since our docking and tabs controls (they're the same control for us, since we've switched to Actipro's UIStudio) have to be hosted in WinForms, and you can't have a WinForms host inside a WPF host inside a WinForms host (the interop facilities of WPF only allow WF inside WPF or WPF inside WF, but not 'double' nesting), we MUST use WinForms for our main application (this sucks since it means we lose a bunch of the nice features of WPF, like commands, command bindings, routed events, etc.).&lt;br /&gt;&lt;br /&gt;This also means that EVERY WPF control in our app must be hosted inside a WPF element host (interop) control on the WinForms form.&lt;br /&gt;&lt;br /&gt;Yuck.  That's a hell of a lot of interop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-8147211776564792629?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/8147211776564792629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=8147211776564792629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8147211776564792629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8147211776564792629'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/interop-interop-and-more-interop.html' title='Interop, Interop, and more Interop'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-5012697222281746231</id><published>2008-02-20T21:47:00.001-08:00</published><updated>2008-02-20T22:00:07.613-08:00</updated><title type='text'>Portrait Mode</title><content type='html'>So, have you guys heard of "Portrait mode" for monitors?  If not, you should really check these out - here's an example of what it is:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://reviews.cnet.com/4520-7610_7-5084364-3.html"&gt;http://reviews.cnet.com/4520-7610_7-5084364-3.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It turns out that portrait mode is actually a feature of your video card, not your monitor.  What makes it a "feature" of the monitor is simply that a monitor that supports portrait mode must have a stand that allows you to rotate the monitor.&lt;br /&gt;&lt;br /&gt;So...  it turns out that the Dell 20" Widescreen LCD panel that I've had on my desk in the Milliman office for 6 months now is actually a 'portrait-capable' monitor.  Of course I had to hire a new employee in order to figure that out :)&lt;br /&gt;&lt;br /&gt;Of course, after setting up my monitor at the office to do portrait mode, I decided I needed to check to see if my Samsung SyncMaster 225BW supported it (my home monitor).  After doing a web search, it seemed that it didn't, so I did some investigating of my own.  This monitor is absolutely awesome, and this is the very first design 'flaw' I've seen with it so far.  However, it turns to be a weirdly long-sighted and simultaneously short-sighted design!&lt;br /&gt;&lt;br /&gt;The stand on the 225BW is removable, and has a square mount.  Inside the back of the monitor, the metal substructure has four mounting studs.  Woohoo! I say, it seems like I can rotate this thing after all.  Unfortunately, there are two mounting ears on the stand that fit into some holes in the plastic case in order to ensure that the monitor doesn't pull away from the stand when tilting it (it only mounts with two screws - the top ones).&lt;br /&gt;&lt;br /&gt;So, long story short, I pulled out some cutting tools and cut myself a couple of holes in the plastic case (it's backed by the metal substructure, which I verified before cutting so that I wouldn't damage any components).  Voila! - I now have a portrait mode monitor!  I can fit 351 code lines in visual studio on one screen given my current toolbar settings (and the error list/bottom windows unpinned) - WAY COOL!  I can taste the productivity already!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-5012697222281746231?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/5012697222281746231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=5012697222281746231' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5012697222281746231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5012697222281746231'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/portrait-mode.html' title='Portrait Mode'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7573627078580624556</id><published>2008-02-11T14:29:00.001-08:00</published><updated>2008-02-11T14:29:47.626-08:00</updated><title type='text'>Collections library for .NET</title><content type='html'>Here's a neat collections library somebody just mentioned in one of the newsgroups I frequent.  I haven't had a chance to check it out much yet, but it seems very promising.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.itu.dk/research/c5/"&gt;http://www.itu.dk/research/c5/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7573627078580624556?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7573627078580624556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7573627078580624556' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7573627078580624556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7573627078580624556'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/collections-library-for-net.html' title='Collections library for .NET'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7783794388842256461</id><published>2008-02-09T22:56:00.000-08:00</published><updated>2008-02-09T22:59:23.242-08:00</updated><title type='text'>Interesting Blog Post - SKU driven development</title><content type='html'>Jeff has a very good post here.  Mostly, I like the bulleted list in the post, I think it's one of the best lists of 'must read topics' I've ever seen in one place.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.moserware.com/2008/02/sku-driven-development.html"&gt;http://www.moserware.com/2008/02/sku-driven-development.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7783794388842256461?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7783794388842256461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7783794388842256461' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7783794388842256461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7783794388842256461'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/interesting-blog-post-sku-driven.html' title='Interesting Blog Post - SKU driven development'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-2793659629031166232</id><published>2008-02-08T09:32:00.000-08:00</published><updated>2008-02-08T09:50:03.197-08:00</updated><title type='text'>BNF in code?</title><content type='html'>Ok... this is pretty cool.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.codeplex.com/irony"&gt;http://www.codeplex.com/irony&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I was very surprised this works.  I wonder how expressive you can really be with this, but it's an interesting idea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-2793659629031166232?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/2793659629031166232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=2793659629031166232' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2793659629031166232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2793659629031166232'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/bnf-in-code.html' title='BNF in code?'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-6292955846555809669</id><published>2008-02-06T15:53:00.001-08:00</published><updated>2008-02-06T15:57:00.038-08:00</updated><title type='text'>NETfx source code...</title><content type='html'>Get it while it lasts!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=2169"&gt;http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=2169&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Chris blogs about a tool that will let you get the whole distro in one fell swoop!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-6292955846555809669?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/6292955846555809669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=6292955846555809669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6292955846555809669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/6292955846555809669'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/netfx-source-code.html' title='NETfx source code...'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7824788820023573187</id><published>2008-02-02T21:22:00.000-08:00</published><updated>2008-02-02T21:23:37.018-08:00</updated><title type='text'>VS2008 and .NETfx source code!!!</title><content type='html'>Check out this post!  I haven't tried it yet, but I'm really hoping it works.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx"&gt;http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7824788820023573187?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7824788820023573187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7824788820023573187' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7824788820023573187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7824788820023573187'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/02/vs2008-and-netfx-source-code.html' title='VS2008 and .NETfx source code!!!'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-2437464977399793005</id><published>2008-01-31T21:57:00.000-08:00</published><updated>2008-01-31T21:58:14.680-08:00</updated><title type='text'>Job Opening</title><content type='html'>We have a job opening for a C# developer on our MG-ALFA development team.  If you're interested, contact me soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-2437464977399793005?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/2437464977399793005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=2437464977399793005' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2437464977399793005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/2437464977399793005'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/01/job-opening.html' title='Job Opening'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-139500013221591868</id><published>2008-01-31T20:05:00.000-08:00</published><updated>2008-01-31T20:59:04.334-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='serialization'/><category scheme='http://www.blogger.com/atom/ns#' term='remoting'/><category scheme='http://www.blogger.com/atom/ns#' term='AppDomain'/><title type='text'>Executing code in another app domain.</title><content type='html'>Recently, we found out that the Infragistics controls we're using have some bugs in them that cause them to never be garbage collected once you've used them in your code. There doesn't seem to be any resolution short of asking them to fix the bugs, as the bugs are related to their code adding event handlers for receiving notification of changes in the office 2007 themes container (their internal class).&lt;br /&gt;&lt;br /&gt;Anyway, we figured out that there isn't any workaround for this short of modifying and recompiling their code or waiting for them to fix their bugs. Since we don't have time for that, and it represents a HUGE memory leak in our application (each time our form is opened and closed, the UI sucks up 30-50MB of additional memory!)&lt;br /&gt;&lt;br /&gt;So, our solution, you ask? We first built an out of process approach to executing our UI via IDispatch implemented in a out-of-process .EXE COM server. This was a fair amount of work and was a really cool project in and of itself. If you're interested in it, let me know and I'll tell you how it works. Unfortunately, due to changes in windows rules for window activation and some plumbing issues, it turns out that the out-of-process approach won't activate the window when it starts up, and short of doing some really nasty hack, there isn't an easy fix for that.&lt;br /&gt;&lt;br /&gt;When we figured the out-of-process solution wasn't really the best answer for our problems, we decided to investigate further. Once we determined that the leak was on our .NET side of the fence (our .NET UI is called by a Dyalog APL-based user interface via their .NET interop support), we decided to investigate the .NET side a bit more. That's when we found that it was a leak caused by the Infragistics controls.&lt;br /&gt;&lt;br /&gt;I did a proof of concept that created a separate AppDomain, called our NUI, and then shutdown the app domain. This seems to fix our memory leak problem as all memory associated with the app domain is freed (at least it seems to be). It turned out to be much harder to get this working than I had expected. In theory it's quite easy, but we have several deployment issues that make it very difficult (we can't put our DLLs in the GAC, and our application DLLs are not (and can't be) in the same folder as the 'application base' (because the base application that creates the main app domain is Dyalog.exe or DyalogRT.exe and we don't want this in our application folder).&lt;br /&gt;&lt;br /&gt;The process goes something like this:&lt;br /&gt;1) create an app domain&lt;br /&gt;2) load our assembly into the domain&lt;br /&gt;3) create a serializable object with our arguments for the call to the assembly&lt;br /&gt;4) call to the assembly (serializing the arguments) (blocking call)&lt;br /&gt;5) the assembly returns from the call, returning the results in a serializable object&lt;br /&gt;6) the calling code deserializes the object and continues as it normally would.&lt;br /&gt;&lt;br /&gt;The problems in this are: (2) finding the assembly; (3) making the serialized object's assembly available to the target assembly; (4) getting a reference to a MarshalByRefObject to make the call against; (5) loading the results objects assembly in the source app domain.&lt;br /&gt;&lt;br /&gt;The main issues are loading the assemblies on the caller's side, rather than the target side, amazingly! It seems like this should be the easy part, but for some reason the remoting infrastructure isn't smart enough to realize that the assemblies are ALREADY LOADED!&lt;br /&gt;&lt;br /&gt;Anyway, the basics are like this:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;create an object that derives from MarshalByRefObject. Put this in an assembly that you don't mind having loaded in both app domains.&lt;/li&gt;&lt;li&gt;define a method on this object that does the work you want done.&lt;/li&gt;&lt;li&gt;make sure that the objects you pass to and from the method are marked Serializable (and can be serialized and deserialized - you can test this by using the BinaryFormatter to write and read the file to/from a stream).&lt;/li&gt;&lt;li&gt;create a method somewhere in your main app domain that does the following: &lt;ol&gt;&lt;li&gt;packages the parameters into the serializable objects&lt;/li&gt;&lt;li&gt;creates an app domain using AppDomain.CreateDomain. We also pass a different appbase that is based on our assemblies' locations.&lt;/li&gt;&lt;li&gt;sets up an event handler on the current app domain's AssemblyResolve event (this is only necessary if you can't get the app domain to properly resolve your assembly and instead your object comes back only as MarshalByRefObject, instead of what you expected).&lt;/li&gt;&lt;li&gt;call CreateInstanceAndUnwrap on the target app domain, asking it to create an instance of your MarshalByRefObject derived object.&lt;/li&gt;&lt;li&gt;cast the object from CreateInstanceAndUnwrap to your target object type.&lt;/li&gt;&lt;li&gt;Call your method.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;Put code in the method handler (if you need it) for your AssemblyResolve event that iterates through the loaded assemblies and returns the one that was requested, if it matches by name. ResolveEventArgs.Name should be matched against Assembly.FullName. My code looks like:&lt;br /&gt;&lt;pre&gt;static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)&lt;br /&gt;{&lt;br /&gt;    Debug.WriteLine("Attempting to resolve assembly: "&lt;br /&gt;        + args.Name);&lt;br /&gt;    // search the loaded assemblies for this one.&lt;br /&gt;    foreach (Assembly assy&lt;br /&gt;                in AppDomain.CurrentDomain.GetAssemblies())&lt;br /&gt;        if (assy.FullName == args.Name)&lt;br /&gt;            return assy;&lt;br /&gt;    return Assembly.GetExecutingAssembly().FullName&lt;br /&gt;        == args.Name&lt;br /&gt;        ? Assembly.GetExecutingAssembly() : null;&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Write code to unload the AppDomain (call AppDomain.Unload(...)) (I do this in a 'finally' that follows a 'try' started immediately after the app domain is created)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This seems to do the trick. Let me know if you have any problems.&lt;/p&gt;&lt;p&gt;Here's where I got some of my information:&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx"&gt;http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx"&gt;http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.codeguru.com/forum/showthread.php?t=398030"&gt;http://www.codeguru.com/forum/showthread.php?t=398030&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx"&gt;http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx"&gt;http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;By the way, if you've never come across it, Suzanne's blog is a GREAT source of information.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-139500013221591868?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/139500013221591868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=139500013221591868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/139500013221591868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/139500013221591868'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/01/executing-code-in-another-app-domain.html' title='Executing code in another app domain.'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4461520238225377779</id><published>2008-01-24T21:25:00.000-08:00</published><updated>2008-01-24T22:03:54.725-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>WPF Data Binding in code</title><content type='html'>Recently, I was working on a WPF prototype for our application. Unfortunately, we need some features in a grid control and some other controls that won't allow us to use the WPF grids available on the market. For this reason, we need to use the Infragistics grid (the same one we've used in the past), the WinForms version.&lt;br /&gt;&lt;br /&gt;Unfortunately, we also need to have docking (VS 2005 style) and tabbed MDI. Since docking has flyout controls, and WPF z-order doesn't work right with WinForms, we need to host our application in Windows Forms framework.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;When you have a windows forms control in a WPF layout, the windows forms control (in the WindowsFormsHost control of WPF) doesn't participate in the z-order the way you might expect. Unfortunately, windows HWNDs don't support layering like WPF (DirectX) does, instead each HWND owns its part of the screen (except for areas overlapped by overlapping windows). Transparency in HWNDs is done by 'hacks', not builtin support.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Due to this structure, winforms controls must be rendered 'on top' of WPF content, when you host winforms in WPF windows. This means my flyout windows will show up "under" the winforms window, rather than on top of it like you'd expect. Anyway, the only way to get around this is to host WPF controls in WinForms rather than the other way around.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;One of the real benefits of using WPF is the XAML markup and the ability to do data binding so easily in your layouts. Unfortunately, at first glance, this seems to be lost when you switch to WPF controls on top of a WinForms layout. Don't fear, all is not lost.&lt;br /&gt;&lt;br /&gt;Fortunately, even though you can't use XAML markup to define your data binding, you can programmatically add bindings to your winforms layout.  For instance, we have a infragistics grid (a winforms control) that lists the 'items' in our browser that people can choose to look at.  On the other hand, we have WPF controls that react to which item is selected in the browser grid.  It'd be nice if we could bind the WPF controls to a property on the other control so that they are automatically updated when necessary.&lt;br /&gt;&lt;br /&gt;The way I did this was to create a DependencyObject that contains my properties for the grid that I'd like to bind to - in particular one of them was CurrentItem.  The properties are DependencyProperty-based.  Now, I needed one-way binding to update my WPF controls when the current item changed in the grid, but just in case, I set up my code to support two way binding, so that if I chose to set the value of the property from other parts of my code, I could do so safely and have everything update properly.&lt;br /&gt;&lt;br /&gt;So, now I have a DO with a DP.  When I register the DP, I created a update method so that I could trigger code when the property was changed - this is done by adding a delegate to the UIPropertyMetadata constructor passed in the DependencyProperty.Register call.  To expose this DO to my clients (I've called it BindingInterfaceObject), I make a property on my UserControl (that contains the Infragistics Grid) called BindingInterface and create an instance of the BindingInterfaceObject in the constructor of the UserControl.  I give it access to the UserControl's private members by making it a nested class and passing the 'this' pointer to its constructor.&lt;br /&gt;&lt;br /&gt;In order to bind to it, I need to set bindings on my WPF controls.  I do this by creating a Binding object (System.Windows.Data.Binding) with the name of the property in BindingInterfaceObject that I care about (in my case CurrentItem) and pass this binding object to the SetBinding method on the WPF controls.&lt;br /&gt;&lt;br /&gt;Voila!  I now have WPF controls binding to changes in a non-WPF control.  The only thing I have to do now is set the CurrentItem property whenever the appropriate event occurs on the grid.  I do this by handling those events in my UserControl and setting the BindingInterface.CurrentItem as appropriate.&lt;br /&gt;&lt;br /&gt;I can provide sample code if you're interested.  Just ask.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4461520238225377779?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4461520238225377779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4461520238225377779' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4461520238225377779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4461520238225377779'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2008/01/wpf-data-binding-in-code.html' title='WPF Data Binding in code'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4557483301946917774</id><published>2007-10-30T14:05:00.001-07:00</published><updated>2007-10-30T14:10:58.335-07:00</updated><title type='text'>Raymond Chen - "The Old New Thing" (best book ever)</title><content type='html'>This is the most interesting non-technical (mostly) computer book I've ever seen!  You owe it to yourself to check out Raymond Chen's blog (&lt;a href="http://blogs.msdn.com/oldnewthing/"&gt;here&lt;/a&gt;) and buy his new book "The Old New Thing".  It's great - I'm either laughing or totally nose down entrenched in reading this book - it's so interesting and at times funny too.&lt;br /&gt;&lt;br /&gt;To save you having to look it up, it's a book on the historical development of windows and the 'why' in windows, rather than the 'how'.  There are some really great insights here, especially about UI design, but there are also some amazing tidbits that explain questions that have been floating around in my head for some time (like what's the deal with GlobalAlloc, LocalAlloc, and all that crap!).&lt;br /&gt;&lt;br /&gt;Anyway, check it out - you can buy it by going to his blog (&lt;a href="http://blogs.msdn.com/oldnewthing/"&gt;here&lt;/a&gt;) and clicking the book image in the upper right corner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4557483301946917774?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4557483301946917774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4557483301946917774' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4557483301946917774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4557483301946917774'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/10/raymond-chen-old-new-thing-best-book.html' title='Raymond Chen - &quot;The Old New Thing&quot; (best book ever)'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-8021360515515619086</id><published>2007-10-19T22:48:00.000-07:00</published><updated>2007-10-30T11:47:29.525-07:00</updated><title type='text'>Away for a while...</title><content type='html'>So, I've been away for a while. Sorry about that. I've got a bunch of new topics I'd like to write about, so many I can't choose which to do first.&lt;br /&gt;&lt;br /&gt;1) OpenXML - this is way cool!&lt;br /&gt;2) More about attributes and their use in .NET - building a binary file system engine.&lt;br /&gt;3) WiX&lt;br /&gt;4) .NET 3.0 System.IO.Packaging and it's use for custom apps...&lt;br /&gt;5) .NET 2.0, 3.0, 3.5 relationships and compatibility between them...&lt;br /&gt;6) DLLs, dependencies, and best practices for COM objects that use non-COM dll's for inprocess use.&lt;br /&gt;7) Benefits of MS Gold Partnership.&lt;br /&gt;8) MG-ALFA planned improvements (at least the ones I can talk about)...&lt;br /&gt;&lt;br /&gt;Not sure - any preferences - please email me...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-8021360515515619086?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/8021360515515619086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=8021360515515619086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8021360515515619086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8021360515515619086'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/10/away-for-while.html' title='Away for a while...'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-7030960125447901231</id><published>2007-03-20T17:43:00.000-07:00</published><updated>2007-10-30T11:46:50.071-07:00</updated><title type='text'>Joel on Software</title><content type='html'>Good book, been recommended to me several times in the past, but I finally bought it with the 20% discount here at SD West 2007's book store...&lt;br /&gt;&lt;br /&gt;The details are "Joel on Software" by "Joel Spolsky"... Get a copy yourself. Also, check out Joel's web site at &lt;a href="http://www.joelonsoftware.com/"&gt;http://www.joelonsoftware.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-7030960125447901231?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/7030960125447901231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=7030960125447901231' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7030960125447901231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/7030960125447901231'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/03/joel-on-software.html' title='Joel on Software'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-8875579432505779679</id><published>2007-01-26T08:50:00.000-08:00</published><updated>2007-10-30T11:46:03.262-07:00</updated><title type='text'>Playing with attributes</title><content type='html'>&lt;p&gt;I'm sure by now you've seen all sorts of .NET framework attributes that can be applied to various pieces of code. The most notable of these in my code are FlagsAttribute (for enums), and the XML serialization / Web Services ones (XmlElementAttribute, XmlAttributeAttribute, etc., and WebServiceAttribute). These are very nice and unleash all kinds of built-in behavior in the framework, but did you know you can make your own attributes and use them for your own purposes? That's what this blog entry is all about!&lt;/p&gt;&lt;p&gt;For me, one of the most common problems I face is one in which I would like to use an enumeration for a class member that has a list of choices. Of course, this is a no-brainer to use an enum for this, but often I want to go one step further. Often, I'd like to limit the enum's choices for the class member, based on the value of one or more of the other class members. This problem is very common in heirarchies where you have a shared base class that you want to support a member in that can have values that aren't always applicable to the object.&lt;/p&gt;&lt;p&gt;Let's say for the sake of argument that you have a class A with members x, y, and z. The z member should be a choice of z1, z2, or z3, but each of these choices is only available when the following conditions hold:&lt;/p&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Condition&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Availability&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;x &amp;gt; 0, y anything&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;z1 z2 available, z3 not&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;x = 0, y &amp;gt; 0&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;z1 available, z2, z3 not&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;x = 0, y &amp;lt; 0&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;z2 available, z1, z3 not&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;x &amp;lt; 0, y anything&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;z3 available, z1, z2 not&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;We can see that these rules can be distilled into a separate "test function" for each value of z. For z1, it's available if x&amp;gt;0  (x == 0 &amp;amp;&amp;amp; y&amp;gt;0). For z2, it's available if x&amp;gt;0  (x == 0 &amp;amp;&amp;amp; y&amp;lt;0). For z3, it's available if x&amp;lt;0 only.&lt;/p&gt;&lt;p&gt;Now, I crashed my compiler in the process of trying to use anonymous delegates to express these conditions. Unfortunately, that doesn't seem to work. However, we can package these three tests into a helper class that provides static methods to perform these tests. For instance, let's make a class ZValueTests as follows:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;  public static class ZValueTests&lt;br /&gt;  {&lt;br /&gt;    public static bool TestForZ1(int x, int y)&lt;br /&gt;    {&lt;br /&gt;      return x&amp;gt;0  (x == 0 &amp;amp;&amp;amp; y&amp;gt;0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static bool TestForZ2(int x, int y)&lt;br /&gt;    {&lt;br /&gt;      return x&amp;gt;0  (x == 0 &amp;amp;&amp;amp; y&amp;lt;0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static bool TestForZ3(int x, int y)&lt;br /&gt;    {&lt;br /&gt;      return x&amp;lt;0;&lt;br /&gt;    }&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;Now that we have these tests, we can use them in an attribute that we apply to each of our enum values. Let's first define our attribute class. We'll call it ValidForAttribute, and it must derive from the Attribute class to be known by the compiler. We'll have to use reflection to call the test functions, so this will be a fun demo in many ways! Here's our attribute declaration.&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;  [AttributeUsage(AttributeTargets.Field)]&lt;br /&gt;  public class ValidForAttribute : Attribute&lt;br /&gt;  {&lt;br /&gt;    private SR.MethodInfo _Test;&lt;br /&gt;&lt;br /&gt;    public ValidForAttribute(&lt;br /&gt;         Type TestClass,&lt;br /&gt;         string MethodName)&lt;br /&gt;    {&lt;br /&gt;      SR.MethodInfo mi&lt;br /&gt;        = TestClass.GetMethod(MethodName);&lt;br /&gt;      // assertions omitted for brevity&lt;br /&gt;      _Test = mi;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public bool Test(int x, int y)&lt;br /&gt;    {&lt;br /&gt;      return (bool)_Test.Invoke(&lt;br /&gt;        null,&lt;br /&gt;        new object[] { x, y });&lt;br /&gt;    }&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;As you can see from the declaration, we'll need to specify our attribute using the type of the class that implements our tests, and the name of the method on that class. This is because we can't use non-constant expressions in the attribute initializer (a pretty big limitation if you ask me), so we can't even use delegate creation expressions, much less anonymous methods! Anyway, this works, it's just a little less pleasant than I would have liked.&lt;/p&gt;&lt;p&gt;Now, we need to declare our actual Enum. You'll see it will be very easy and will look something like the following:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;  public enum ZValue&lt;br /&gt;  {&lt;br /&gt;    [ValidFor(typeof(ZValueTests), "TestForZ1")]&lt;br /&gt;    z1,&lt;br /&gt;    [ValidFor(typeof(ZValueTests), "TestForZ2")]&lt;br /&gt;    z2,&lt;br /&gt;    [ValidFor(typeof(ZValueTests), "TestForZ3")]&lt;br /&gt;    z3&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;This is very pleasant as it very clearly defines the test functions that apply to each z value. Of course, one unpleasant thing is that the types of these functions cannot be checked until runtime (that's what the asserts that are omitted from the code in the attribute do). I would recommend even throwing an exception if the function isn't declared right from the constructor of the attribute, but that may be a bit harsh.&lt;/p&gt;&lt;p&gt;Now, I've shown how you can declare the enums, attribute class, and test class - but what we really want to see is the validation in action, right? So, here we go. If we declare the class A as follows:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;public class A {&lt;br /&gt;  ZValue _z;&lt;br /&gt;&lt;br /&gt;  bool ValidateZ(int x, int y, ZValue z) {&lt;br /&gt;    SR.FieldInfo fi = typeof(ZValue)&lt;br /&gt;      .GetField(Enum.GetName(&lt;br /&gt;        typeof(ZValue), z));&lt;br /&gt;    // test all attrs (ValidForAttribute)&lt;br /&gt;    if(fi != null)&lt;br /&gt;      foreach(ValidForAttribute vfa&lt;br /&gt;           in fi.GetCustomAttributes(&lt;br /&gt;                 typeof(ValidForAttribute),&lt;br /&gt;                 true))&lt;br /&gt;        if (vfa.Test(x, y))&lt;br /&gt;          return true;&lt;br /&gt;    // ret false if enum not found,&lt;br /&gt;    //   or no attrs found returning true&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int x, y;&lt;br /&gt;  public ZValue z&lt;br /&gt;  {&lt;br /&gt;    get { return _z; }&lt;br /&gt;    set {&lt;br /&gt;      if(ValidateZ(x, y, value))&lt;br /&gt;        _z = value;&lt;br /&gt;      else&lt;br /&gt;        throw new Exception(&lt;br /&gt;          string.Format(&lt;br /&gt;            "Invalid z: ({0}, {1}, {2})",&lt;br /&gt;            x, y, z));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;then the code will validate a new value of z against x and y before setting the internal field (_z) to that value. An exception will be raised if the value is invalid. This may seem like a lot of work, instead of just validating z inside the z "set" accessor. That's true, it is. However, the real advantage to this is that the validation code can be used in other ways. For instance, consider if we wanted a list of valid values for z (for a UI, for instance) given a particular value of x and y. We can write the following code:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;public static ZValue[] ValidZs(int x, int y) {&lt;br /&gt;  List&amp;lt;ZValue&amp;gt; zv = new List&amp;lt;ZValue&amp;gt;(&lt;br /&gt;    (IEnumerable&amp;lt;ZValue&amp;gt;)&lt;br /&gt;      Enum.GetValues(typeof(ZValue)));&lt;br /&gt;  zv.RemoveAll(new Predicate&amp;lt;ZValue&amp;gt;(&lt;br /&gt;    delegate(ZValue v)&lt;br /&gt;    {&lt;br /&gt;      SR.FieldInfo fi = typeof(ZValue)&lt;br /&gt;        .GetField(Enum.GetName(&lt;br /&gt;                    typeof(ZValue),&lt;br /&gt;                    v&lt;br /&gt;      ));&lt;br /&gt;      if (fi != null)&lt;br /&gt;        foreach (ValidForAttribute vfa&lt;br /&gt;             in fi.GetCustomAttributes(&lt;br /&gt;                 typeof(ValidForAttribute),&lt;br /&gt;                 true))&lt;br /&gt;          if (vfa.Test(x, y))&lt;br /&gt;            return false;&lt;br /&gt;      return true;&lt;br /&gt;    }&lt;br /&gt;  ));&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Hope you found this interesting! Email with questions, if you have them!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-8875579432505779679?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/8875579432505779679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=8875579432505779679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8875579432505779679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/8875579432505779679'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/01/playing-with-attributes.html' title='Playing with attributes'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-5203726189456947664</id><published>2007-01-06T19:10:00.000-08:00</published><updated>2007-10-30T11:45:21.947-07:00</updated><title type='text'>Anonymous Delegates in C#</title><content type='html'>&lt;p&gt;A friend asked me recently what features other than Generics I really liked in C# 2.0. I mentioned that the anonymous delegate is one of those features. So, you might ask, what is an anonymous delegate? First of all, for those of you who don't know what delegates are, they are the C# equivalent of a function pointer, sortof.&lt;/p&gt;&lt;p&gt;A delegate is a strongly typed method pointer, that stores both the method reference and the object reference on which the method is defined. Delegates are declared with the syntax:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;[access] delegate [return type]&lt;br /&gt;   [delegate name] ( [param signatures] )&lt;/pre&gt;&lt;p&gt;where [access] is an access modifier (optional) - public, private, protected, or internal, return type is the return type of methods that will be pointed to by the delegate (or void), and the other items are relatively self-explanatory.&lt;/p&gt;&lt;p&gt;Now. That's how a delegate "type" is declared. However, anonymous delegates aren't really delegate types - they're delegate instances. Let's say we have a delegate called BinaryIntegerOperation declared as:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;public delegate int&lt;br /&gt;  BinaryIntegerOperation (int a, int b);&lt;/pre&gt;&lt;p&gt;This declaration gives us a delegate type called BinaryIntegerOperation. If we want to create a delegate instance, we need to pass the name of a function with the appropriate signature to this delegate's constructor during a invocation of the new operator. Let's assume that we have a class declared as:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;public class Adder {&lt;br /&gt;  public int Add(int x1, int x2) {&lt;br /&gt;    return x1 + x2;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Let's also assume that we have some instance of the Adder class, referenced by a variable called myAdder, within the context of the code we care about. The code to construct a delegate instance of BinaryIntegerOperation using the Add method of our myAdder object instance would look like:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;...&lt;br /&gt;BinaryIntegerOperation op&lt;br /&gt;  = new BinaryIntegerOperation(&lt;br /&gt;    myAdder.Add);&lt;br /&gt;...&lt;/pre&gt;&lt;p&gt;and the code to invoke this delegate would look like:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;int result = op(value1, value2);&lt;/pre&gt;&lt;p&gt;(just like a normal method call).&lt;/p&gt;&lt;p&gt;Now, let's say that instead of declaring an Adder class, we just wanted to be able to pass some simple implementation of the BinaryIntegerOperation delegate's method signature to the delegate's constructor so that we could use it in a context that needs a BinaryIntegerOperation instance. We can do the following, instead of declaring a Adder object altogether:&lt;/p&gt;&lt;p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;BinaryIntegerOperation op&lt;br /&gt;  = new BinaryIntegerOperation(&lt;br /&gt;    delegate (int a, int b) {&lt;br /&gt;      return a + b;&lt;br /&gt;    });&lt;/pre&gt;&lt;p&gt;As you can see from this code, the code for the delegate instance is actually placed inline using the delegate keyword, along with the parameter signatures of the method. C# will automatically create a class, instance, and method for us, so we don't have to do so ourselves.&lt;/p&gt;&lt;p&gt;You might say, what is the advantage of this? I use this feature very extensively, often in code dealing with list filtering or searching.&lt;/p&gt;&lt;p&gt;Let's say you have a list of integers, and you want to determine if any of them is larger than a particular value (say 10).&lt;/p&gt;&lt;p&gt;Consider the code (list is List&amp;lt;int&amp;gt;)&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;bool bigger = false;&lt;br /&gt;foreach(int item in list) {&lt;br /&gt;  if(item &amp;gt; 10) {&lt;br /&gt;    bigger = true;&lt;br /&gt;    break;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;you could instead write it as:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;bool bigger =&lt;br /&gt;  -1 != list.FindIndex(&lt;br /&gt;     new Predicate&amp;lt;int&amp;gt;(&lt;br /&gt;       delegate (int x) {&lt;br /&gt;         return x &amp;gt; 10;&lt;br /&gt;       }));&lt;/pre&gt;&lt;p&gt;where, again, list is List&amp;lt;int&amp;gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-5203726189456947664?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/5203726189456947664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=5203726189456947664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5203726189456947664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/5203726189456947664'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/01/anonymous-delegates-in-c.html' title='Anonymous Delegates in C#'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4119496936270150724</id><published>2007-01-05T19:32:00.000-08:00</published><updated>2007-10-30T11:44:15.777-07:00</updated><title type='text'>The ClickOnce reference (on MSDN)</title><content type='html'>Just in case you want to learn a bit about ClickOnce yourself, from the source, you can do so on the MSDN site here: &lt;a href="http://msdn2.microsoft.com/en-us/library/6ae39a7c(VS.80).aspx"&gt;http://msdn2.microsoft.com/en-us/library/6ae39a7c(VS.80).aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-4119496936270150724?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/4119496936270150724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=4119496936270150724' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4119496936270150724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/4119496936270150724'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/10/clickonce-reference-on-msdn.html' title='The ClickOnce reference (on MSDN)'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-1563817043478576753</id><published>2007-01-05T15:03:00.000-08:00</published><updated>2007-10-30T11:43:13.417-07:00</updated><title type='text'>Clickonce Deployment Tidbits</title><content type='html'>Ok... First, I'm going to talk about CD-ROM based initial installations, 'cause that's what I know best. The scenario where this install type works best is as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Application prerequisites are quite large (SQL Server, stuff like that...)&lt;/li&gt;&lt;li&gt;Application updates should be delivered via the web&lt;/li&gt;&lt;li&gt;Application should be available offline (see the "Offline as well" option in Install Mode and Settings under Publish properties of your VS2005 project).&lt;/li&gt;&lt;li&gt;Application may have custom prerequisites (another article in itself, coming soon).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We typically configure our applications so that they don't have a deployment web page, but either way is fine (this option is in the Options... dialog). For the purposes of discussion, I'm going to assume the program name is MyApp and that the only files deployed with the application will be the app.config and the app exe.&lt;/p&gt;&lt;p&gt;To set up the application to publish to CD-ROM or DVD-ROM, you should choose a publish location that is a file path on your local machine. We typically use c:\deployments\... or something like that. For the purposes of discussion, I'm using c:\deploy\MyApp\v1.0.0.0 as my first deployment location. You'll want to have a version number in your deployment location so that you don't overwrite older deployments when creating new ones.&lt;/p&gt;&lt;p&gt;So, for version 1.0 of our application, we'll set the deployment location to c:\deploy\MyApp\v1.0.0.0. It's tempting to put something in the "Installation URL" but we won't for building the initial CDs to deploy from. It's also tempting to let visual studio automatically increment the revision with each publish. However, we prefer to have total control over the version number used for publish and for the assembly version (stored in the AssemblyInfo.cs file). There are actually a ton of different version numbers floating around in .NET applications. In our simple case here, there's the Deployment version, the Assembly version, and the Assembly file version. We like to keep all of them in sync. Things can get very confusing otherwise. I'm not going to talk much about the significance of each different version number here, unless requested to do so, so make a request if you want more details about them.&lt;/p&gt;&lt;p&gt;So, on to the publish. We're looking to publish our application to a CD, but also to be able to update it from the web. Let's say you have a web server available (we'll use localhost for these examples). If you create a site (or virtual directory) called MyApp on your IIS install, it will be easier to follow my examples. I'm going to use the path &lt;a href="http://localhost/MyApp/updates"&gt;http://localhost/MyApp/updates&lt;/a&gt; as my updates deployment path. So, let's click on the Updates... button and see what we see.&lt;/p&gt;&lt;p&gt;In the updates dialog, we obviously want "Application should check for updates" checked, since that's the whole point of this discussion. I would choose "Before the application starts" for the when, since the other alternative is very strange. For now, leave the "minimum required version" blank. For the update location, let's put our &lt;a href="http://localhost/MyApp/updates"&gt;http://localhost/MyApp/updates&lt;/a&gt; path.&lt;/p&gt;&lt;p&gt;Close the dialog and click publish now. After a few moments, you should see an explorer window pop up with the deployment files in it. Let's look at those files for a moment. There should be a setup.exe - it's the setup bootstrapper that knows how to install your prerequisites and get the ball rolling on the installation. There's also a couple of .application files. The unversioned one and the versioned one are identical (in contents).&lt;/p&gt;&lt;p&gt;These files can be copied to a CD-ROM or DVD-ROM and installed from there, by clicking the Setup.exe. However, we also need to set up the path for updates too. Let's talk about how to deploy the updates to a web server. Whereever you placed your virtual folder (physically) on your web server, you need to copy the .application files and the MyApp_1_0_0_0 folder to that location. In my case, &lt;a href="http://localhost/MyApp"&gt;http://localhost/MyApp&lt;/a&gt; refers to a "C:\MyApp Deployment" folder on my local hard drive. Since I want the files to be in the "./updates" path relative to this virtual folder, I need a "updates" folder in this folder. I then need to copy those files to the "updates" folder. I should make sure the permissions on those files and folders are appropriate for the users I wish to be able to access this application (normally anonymous access is needed if you want to deploy the application to anyone that wants it).&lt;/p&gt;&lt;p&gt;Once you've copied those files and set up those folders, you should be good to go for your first CD-based ClickOnce deployment. Run the setup.exe from the CD to install the application. If you run Setup.exe the app should install (after warning you about security) and then immediately run itself. You'll see that the app should also appear in your start menu and in the add/remove programs control panel applet.&lt;/p&gt;&lt;p&gt;Now, let's update the application and see a new version deployed. In my case, the original application didn't do anything and was simply a blank form (from the new application wizard). To make version 1.1, I'm going to add a label to the form with some text so I can tell I've got the new version. Once you've done that, deploy again, but to a v1.1.0.0 folder, and change the deployment version (and assembly versions in AssemblyInfo.cs) first. Do this by going to the publish properties (in the project properties) and setting the major and minor publish versions as appropriate. Now publish to the new folder. Once the publish is done, you should see the explorer window pop up. Copy the .application files and the MyApp_1_1_0_0 folder to the updates folder in your web server again. This will replace the MyApp.application that was put there for version 1.0.&lt;/p&gt;&lt;p&gt;Now, let's see the application update itself. Click the application from the start menu and see what happens. The application should ask you if you want to update. DON'T click SKIP! It won't ask you again for a long time if you do (I'm not sure how long). If you don't want your users to be able to skip updates, set a required version equal to your current version each time you deploy (in the Updates... dialog of the Publish settings).&lt;/p&gt;&lt;p&gt;Anyway, you've just done your first ClickOnce deployment. More tidbits to come.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8594690550975135798-1563817043478576753?l=kleahy-technical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kleahy-technical.blogspot.com/feeds/1563817043478576753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8594690550975135798&amp;postID=1563817043478576753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1563817043478576753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8594690550975135798/posts/default/1563817043478576753'/><link rel='alternate' type='text/html' href='http://kleahy-technical.blogspot.com/2007/01/clickonce-deployment-tidbits.html' title='Clickonce Deployment Tidbits'/><author><name>Kelly Leahy</name><uri>http://www.blogger.com/profile/01587387873239212889</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8594690550975135798.post-4561395133111864459</id><published>2007-01-04T10:47:00.000-08:00</published><updated>2007-10-30T11:41:48.240-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Xml Serialization with custom collections'/><title type='text'>.NET Xml Serialization with complex collections</title><content type='html'>&lt;p&gt;So, the other day, I was doing some XML serialization work in .NET and I thought to myself, I need some more complex collection members in this XML heirarchy but I'd still like them to be serialized. What do I mean? Well, the default type of collections used by the XML serialization in .NET (if you use xsd.exe to generate the code for your serialization classes) is a strongly typed array. For instance, let's say I have XML that looks like the following:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;&amp;lt;root&amp;gt;&lt;br /&gt;  &amp;lt;entry id="1" value="hello"&amp;gt;&lt;br /&gt;  &amp;lt;entry id="2" value="there"&amp;gt;&lt;br /&gt;&amp;lt;/root&amp;gt;&lt;/pre&gt;&lt;p&gt;Now, let's say I use xsd.exe to generate my code (first I run xsd to infer the schema, then I run it to generate classes for this schema). I'll get two classes - one of them will be called "root" and the other "rootEntry". The class named "root" will get a member called Items declared as&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;private rootEntry[] itemsField;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;remarks/&amp;gt;&lt;br /&gt;[System.Xml.Serialization.XmlElementAttribute("entry",&lt;br /&gt;    Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]&lt;br /&gt;public rootEntry[] Items {&lt;br /&gt;  get {&lt;br /&gt;    return this.itemsField;&lt;br /&gt;  }&lt;br /&gt;  set {&lt;br /&gt;    this.itemsField = value;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;My issue was this - I wanted to use my classes to generate XML, not just read it. In the case of generating XML using these classes, it's a bit of a pain to have to build the array first, before attaching it to the class. It'd be much nicer if I could just have a List&amp;lt;rootentry&amp;gt; as my collection type.&lt;/p&gt;&lt;p&gt;Well, it turns out, that having a List&amp;lt;rootentry&amp;gt; as the collection type of the Items property is quite easy! The .NET framework even knows how to construct it for you, so you don't have to construct it by default. All you need to do is change the declarations above from rootEntry[] to List&amp;lt;rootentry&amp;gt; (include System.Collections.Generic in your using list, of course).&lt;/p&gt;&lt;p&gt;All that is fine, but I would like to use a custom IList&amp;lt;rootentry&amp;gt; implementation so that my collection can have other niceties (like providing notifications when one of the entries has changed in value, etc.), so I want to use my own collection type. At first, I thought I could just derive from List&amp;lt;rootentry&amp;gt; to build my collection type, but unfortunely, most of the stuff in List is not virtual, so it can't be overridden. Therefore, I decided to try building a list object that implements IList&amp;lt;rootentry&amp;gt; and see what happens.&lt;/p&gt;&lt;p&gt;My class was declared like this:&lt;/p&gt;&lt;pre style="FONT-SIZE: 1em"&gt;&lt;br /&gt;public class OwnedList&amp;lt;TElem, TOwner&amp;gt;: IList&amp;lt;TElem&amp;gt; {&lt;br /&gt;  private List&amp;lt;TElem&amp;gt; _Items;&lt;br /&gt;  private TOwner _Owner;&lt;br /&gt;&lt;br /&gt;  public
