<?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:blogger='http://schemas.google.com/blogger/2008' 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-953670387080576871</id><updated>2024-11-01T04:40:15.092-05:00</updated><category term="ASP.NET"/><category term="wpf"/><category term="jQuery"/><category term="mercurial"/><category term="plugin"/><category term="bug"/><category term="visual studio"/><category term="MVC"/><category term="blend"/><category term="branching"/><category term="iPhone"/><category term="iis"/><category term="ncrunch"/><category term="objective-c"/><category term="open source"/><category term="orchard"/><category term="performance"/><category term="resharper"/><category term="service"/><category term="sortable"/><category term="source control"/><category term="testing"/><category term="timeouts"/><category term="validation"/><category term="wcf"/><title type='text'>random.Next()</title><subtitle type='html'>Random posts about .NET, jQuery and other technologies.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-631142637881862115</id><published>2012-05-18T19:18:00.000-05:00</published><updated>2012-05-18T19:18:08.037-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ncrunch"/><category scheme="http://www.blogger.com/atom/ns#" term="plugin"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><category scheme="http://www.blogger.com/atom/ns#" term="visual studio"/><title type='text'>NCrunch</title><content type='html'>If you haven’t seen NCrunch, it’s &lt;b&gt;&lt;i&gt;really &lt;/i&gt;&lt;/b&gt;worth it.  &lt;a href=&quot;http://www.ncrunch.net/&quot;&gt;http://www.ncrunch.net/&lt;/a&gt; 

I recently upgraded it and found a few new features so I figured I would blog about it for those who haven&#39;t used it.

It basically a plugin that is configurable to watch for code changes and re-run tests as you write the code.  This way you have constant feedback as you write the code.  It also puts little dots (or lines, it’s configurable) and has a nice little window you can dock to show you code coverage and # of failing tests.  Checkout my setup below. 

&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijZiJ60FeJY_NmMtIs68A8oXXdFrAgDmawx1gskPs2cvAspevYd6IJ6m3_ZRUOSmZWHWvlyYoXXnZGCX532DQ0y9z1YXRB8b8sXTM4BZqIcC2VFPBywavuX2kagOOvOZzpeuIgJByM45VJ/s1600/ncrunch.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijZiJ60FeJY_NmMtIs68A8oXXdFrAgDmawx1gskPs2cvAspevYd6IJ6m3_ZRUOSmZWHWvlyYoXXnZGCX532DQ0y9z1YXRB8b8sXTM4BZqIcC2VFPBywavuX2kagOOvOZzpeuIgJByM45VJ/s640/ncrunch.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
You’ll see the green lines on the left mean at least 1 passing test is covering that code.  Gray lines are not being covered by any tests.  Red means at least one test is failing.  Red X is a line that is causing a test to fail (via an obvious exception in the example).  Finally, yellow is a performance concern.  You can configure it to turn yellow if any line of code is taking over x milliseconds during a unit test.  Mine is set to 200ms and you can see the ViewBag call is trigging it.  The lines are clickable and show you the tests that are related to that line of code as well as giving you a quick way to jump to each test.

It’s really cool.  You might have to tweak it for performance so that VS doesn’t slow down too much depending on your dev machine&#39;s specs.  It’s totally configurable and you can go as far as only running “pinned” tests so you can choose which ones you care about while you are actively coding.  Then running them all later once you’re done with your coding session.</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/631142637881862115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2012/05/ncrunch.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/631142637881862115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/631142637881862115'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2012/05/ncrunch.html' title='NCrunch'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijZiJ60FeJY_NmMtIs68A8oXXdFrAgDmawx1gskPs2cvAspevYd6IJ6m3_ZRUOSmZWHWvlyYoXXnZGCX532DQ0y9z1YXRB8b8sXTM4BZqIcC2VFPBywavuX2kagOOvOZzpeuIgJByM45VJ/s72-c/ncrunch.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-8750993461813012629</id><published>2011-05-13T10:23:00.000-05:00</published><updated>2011-05-24T14:09:53.404-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="resharper"/><category scheme="http://www.blogger.com/atom/ns#" term="visual studio"/><title type='text'>Is ReSharper 5.1 slowing down Visual Studio?</title><content type='html'>&lt;p&gt;I recently had some slowdowns that I attributed to &lt;a href=&quot;http://www.jetbrains.com/resharper/&quot;&gt;ReSharper&lt;/a&gt;.&amp;#160; On every file save, the machine would freeze for a good 1-2 seconds.&amp;#160; That gets old really quickly.&amp;#160; Disabling ReSharper fixes the issue, but a fellow developer had no issues with speed with all the same settings.&amp;#160; After fighting with it for a couple days I finally remember to try and turn off &lt;a href=&quot;http://visualhg.codeplex.com/&quot;&gt;VisualHG&lt;/a&gt;, my source control plugin.&amp;#160; After turning it off, the problem is gone and I can re-enable ReSharper.&amp;#160; I would much rather have ReSharper than VisualHG.&amp;#160; I typically never use VisualHG, it’s just never been a problem before so I left it on.&amp;#160; I’m not sure which team is responsible (if any) for the conflict, but I hope this post helps someone out.&lt;/p&gt;  &lt;p&gt;If you use Visual Studio 2010 and have random slowdowns or aren’t impressed with the speed in general, you should be running &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/fa85b17d-3df2-49b1-bee6-71527ffef441?SRC=Home&quot;&gt;Visual Studio PerfWatson&lt;/a&gt;.&amp;#160; Read more &lt;a href=&quot;http://blogs.msdn.com/b/visualstudio/archive/2011/05/02/perfwatson.aspx&quot;&gt;here&lt;/a&gt;. Developers owe it to themselves to run this plugin and report anything.&amp;#160; I’m hoping the IE9 feature that tells you which plugins are resulting in a slow startup time makes its way to Visual Studio as well.&amp;#160; That way the pressure for the best feature of any software, speed, is placed squarely on the developers of the plugins.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/8750993461813012629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/05/is-resharper-51-slowing-down-visual.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/8750993461813012629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/8750993461813012629'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/05/is-resharper-51-slowing-down-visual.html' title='Is ReSharper 5.1 slowing down Visual Studio?'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-3461079925604810801</id><published>2011-04-12T11:23:00.000-05:00</published><updated>2011-04-12T11:23:00.169-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iis"/><category scheme="http://www.blogger.com/atom/ns#" term="mercurial"/><title type='text'>Setting up a Mercurial Server using IIS 7</title><content type='html'>&lt;p&gt;If you need to setup a central mercurial server, follow these steps. &lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;http://www.sjmdev.com/blog/post/2011/03/30/setting-mercurial-18-server-iis7-windows-server-2008-r2.aspx&quot; href=&quot;http://www.sjmdev.com/blog/post/2011/03/30/setting-mercurial-18-server-iis7-windows-server-2008-r2.aspx&quot;&gt;http://www.sjmdev.com/blog/post/2011/03/30/setting-mercurial-18-server-iis7-windows-server-2008-r2.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The only thing I would advice against would be using the re-write module.&amp;#160; It has a query string length limitation of 2050 characters.&amp;#160; Mercurial uses, in my opinion, the query string in a bad way when pushing changesets.&amp;#160; It really should use the POST for any large amount of data, but it uses the query string currently for some part of the POST.&amp;#160; This causes IIS to return a 404.&amp;#160; The limitation is easily avoided by not using the rewrite module.&amp;#160; You just have to deal with ugly URLs.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/3461079925604810801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/04/setting-up-mercurial-server-using-iis-7.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3461079925604810801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3461079925604810801'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/04/setting-up-mercurial-server-using-iis-7.html' title='Setting up a Mercurial Server using IIS 7'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-5854180329364363687</id><published>2011-02-21T22:53:00.000-06:00</published><updated>2011-02-21T22:53:00.903-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bug"/><category scheme="http://www.blogger.com/atom/ns#" term="service"/><category scheme="http://www.blogger.com/atom/ns#" term="timeouts"/><category scheme="http://www.blogger.com/atom/ns#" term="wcf"/><title type='text'>WCF Service Side Timeouts</title><content type='html'>&lt;p&gt;Recently I have discovered that WCF &lt;strong&gt;doesn’t&lt;/strong&gt; support service-side timeouts.&amp;#160; For a great code example and explanation of behavior check out this post on my favorite QA site, &lt;a href=&quot;http://stackoverflow.com/questions/4974640/why-doesnt-wcf-support-service-side-timeouts/4974721&quot;&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I know you’re probably thinking “don’t right code that runs too long” or something along those lines.&amp;#160; In high concurrency systems, any number of things could cause code to run abnormally long lengths of time.&amp;#160; Just think about DTS (Distributed Transactions) as well as 3rd party system integrations.&lt;/p&gt;  &lt;p&gt;The basic problem is as stated in the post, the code running on the server never stops.&amp;#160; This is the equivalent of IIS not having timeouts.&amp;#160; &lt;strong&gt;Ludicrous.&lt;/strong&gt;&amp;#160; The current solution is to write error-prone thread abort code ourselves.&amp;#160; It gets even weirder with WCF as you have client timeouts you can set.&amp;#160; So you can set a nice 20 second client timeout and the client will get a nice fault saying the operation timed out.&amp;#160; Good right?&amp;#160; No.&amp;#160; The client has been disconnected, but the code is continuing on like nothing happened on the service.&lt;/p&gt;  &lt;p&gt;Well I know it probably doesn’t apply to a lot of people, but I needed somewhere to vent about it.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/5854180329364363687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/02/wcf-service-side-timeouts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5854180329364363687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5854180329364363687'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/02/wcf-service-side-timeouts.html' title='WCF Service Side Timeouts'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-3482467565785247613</id><published>2011-02-03T11:48:00.000-06:00</published><updated>2012-05-18T20:06:10.167-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="plugin"/><category scheme="http://www.blogger.com/atom/ns#" term="sortable"/><title type='text'>jQuery UI Sortable with tables</title><content type='html'>&lt;p&gt;&lt;em&gt;note: If you have &lt;strong&gt;any&lt;/strong&gt; other option besides trying to drag table rows, pretend this post doesn’t exist and use divs.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;If you have a need for drag and drop functionality, look no further than &lt;a href=&quot;http://jqueryui.com/demos/sortable/&quot;&gt;jQuery UI’s sortable plugin&lt;/a&gt;.&amp;#160; If you need to drag and drop table rows, you’ll need to help the plugin along to ensure your table looks correct when dragging rows around.&amp;#160; Luckily the plugin exposes an option called &lt;a href=&quot;http://jqueryui.com/demos/sortable/#option-helper&quot;&gt;helper&lt;/a&gt;.&amp;#160; This function simply runs when a draggable item is being moved.&amp;#160; This code below is pretty nasty, but it makes sure your dynamic width table looks great when dragging. &lt;/p&gt;  &lt;pre class=&quot;py&quot; name=&quot;code&quot;&gt; var tableRowHelper = function(e, ui) {
 ui.children().each(function() {
  var newWidth = $(this).css(&#39;width&#39;);
  if (newWidth == &#39;auto&#39; || newWidth == &#39;&#39;) {
   newWidth = $(this).width() + &#39;px&#39;;
  }
  $(this).css(&#39;width&#39;, newWidth);
 });
 return ui;
 }; 

// usage
$(&#39;#someId&#39;).sortable({
 helper: tableRowHelper 
});&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/3482467565785247613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/02/jquery-ui-sortable-with-tables.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3482467565785247613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3482467565785247613'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/02/jquery-ui-sortable-with-tables.html' title='jQuery UI Sortable with tables'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-6692485718709888813</id><published>2011-01-26T10:49:00.000-06:00</published><updated>2011-01-26T10:49:00.386-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="open source"/><category scheme="http://www.blogger.com/atom/ns#" term="orchard"/><title type='text'>Thoughts on Orchard</title><content type='html'>&lt;p&gt;In case you aren’t aware, there is a new .NET based CMS system that just had it’s first release.&amp;#160; &lt;a href=&quot;http://www.orchardproject.net/&quot;&gt;Orchard&lt;/a&gt;.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Orchard is a &lt;strong&gt;free, open source, community-focused&lt;/strong&gt; project aimed at delivering applications and reusable components on the ASP.NET platform.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font color=&quot;#000000&quot; face=&quot;Arial&quot;&gt;I’ve been keeping my eye on this project for some time and almost replaced this very blog with it.&amp;#160; In the end I decided against it, but mostly because the blog platform is “solved”.&amp;#160; I don’t need to re-invent the wheel yet again.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;If you’re looking to familiarize yourself with ASP.NET MVC and see how it scales to a very complex project, this is a great example.&amp;#160; They use the latest bits of MVC 3, including razor as the view engine of choice.&amp;#160; &lt;a href=&quot;http://www.orchardproject.net/download&quot;&gt;Download Orchard&lt;/a&gt; and start browsing the source.&amp;#160; If you don’t care about the source and just want a good CMS, make sure to pick the web platform installer version, it’ll make setting it up a breeze.&lt;/p&gt;  &lt;p&gt;&lt;font color=&quot;#000000&quot; face=&quot;Arial&quot;&gt;Developing for Orchard is pretty straight forward.&amp;#160; Every module is essentially a MVC Area.&amp;#160; They even created a command line utility to generate out the default module layout.&amp;#160; I really like some of the convention-based pieces like the data migrations.&amp;#160; &lt;font color=&quot;#000000&quot; face=&quot;Arial&quot;&gt;If you haven’t done so already, &lt;a href=&quot;http://www.orchardproject.net/docs/&quot;&gt;read the documentation&lt;/a&gt; and follow through with some tutorials on creating modules.&amp;#160; It’s quite easy once you learn the lingo of the project.&amp;#160; It has a very clear separation of concerns in all the layers.&amp;#160; They also did a good job &lt;a href=&quot;http://en.wikipedia.org/wiki/Eating_your_own_dog_food&quot;&gt;dogfooding&lt;/a&gt; their own module api with the default modules so browsing the existing modules is very useful.&amp;#160; &lt;/font&gt;By the way, if you don’t have visual studio, you can still develop modules.&amp;#160; Orchard uses a &lt;a href=&quot;http://orchardproject.net/docs/Orchard-module-loader-and-dynamic-compilation.ashx&quot;&gt;dynamic compilation&lt;/a&gt; process to compile source-only deployed modules.&amp;#160; This should help Orchard when it comes to a growing community, paving the way for the the Mono enthusiasts to pick it up.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color=&quot;#000000&quot; face=&quot;Arial&quot;&gt;I’ll be looking to commit some modules in the not-so-distant future and I’ll post a how-to here when I do.&lt;/font&gt;&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/6692485718709888813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/01/thoughts-on-orchard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/6692485718709888813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/6692485718709888813'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/01/thoughts-on-orchard.html' title='Thoughts on Orchard'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-5444760947807009294</id><published>2011-01-21T09:00:00.007-06:00</published><updated>2011-01-21T09:00:06.236-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="branching"/><category scheme="http://www.blogger.com/atom/ns#" term="mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="source control"/><title type='text'>Mercurial: Named Branch Workflow</title><content type='html'>&lt;p&gt;&lt;em&gt;Note: This is what works for us, you may decide this sounds insane. You are allowed that opinion ;)&lt;/em&gt;&lt;/p&gt;&lt;p&gt;We recently made the switch to using Mercurial (Hg) in our office and I dare say productivity has been through the roof compared to what now appears to be an archaic way of source control, known as subversion.&amp;#160; I won’t go into why we decided on Mercurial in this post but rather how we are using it today and what rocks about it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;font size=&quot;4&quot;&gt;The Workflow&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;At our company we have many products under a single umbrella with many pieces of shared code and functionality between the products.&amp;#160; I imagine many companies have very similar setups.&amp;#160; We have around 8 developers divided into teams.&amp;#160; Each team has their own set of goals and features for their next release for their product.&amp;#160; As you can imagine, having this many developers working on a single codebase that shares a lot of core functionality can be a bit complex.&amp;#160; For this example I’ll setup a blank repository and use TortoiseHg’s visual tools to help show the progress as we move along.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYWLdQ6NJJoGHe9fXGtH1KoZGcZzxuO4tSCx9rvVGt43ma7m1ayaJuEJ3vz6G4qu5BHAxdxIccV5Amu95KetpQygCEBdLyAV2naqR8aNkj8aNy9uU8qp3IStEc7zpvFGIQ5FxwSuhZ2213/s1600-h/image3.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgutHrTlNEhW6s8TxFHvnIPWSk6SLIw2TD0ByRYKs3lymGkmoQ0uDJj0k9ZizYu2eswoB6jsNcDOj_fd7Rt2LQgv3Pomkax8mUVjtWcSqD1AEi0kJOzqS8UTmDGXa_07y2wqkRkF5rp3i6u/?imgmax=800&quot; width=&quot;787&quot; height=&quot;190&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As you can see above, we have a brand new repository with a single commit.&amp;#160; Now lest assume we have two teams and they both have features to develop simultaneously.&amp;#160; In this workflow, we branch per feature.&amp;#160; The branch also must be a &lt;strong&gt;named branch&lt;/strong&gt;.&lt;strong&gt;&amp;#160; &lt;/strong&gt;This is great for clarity purposes, but we also use this for another reason I’ll explain later.&amp;#160; &lt;/p&gt;&lt;p&gt;This is where things diverge from a “normal” mercurial workflow.&amp;#160; Mercurial, by default, only allows one head per repository.&amp;#160; This is how most projects work and for good reasons.&amp;#160; There is only ever one release so there only needs to be one branch head.&amp;#160; &lt;/p&gt;&lt;p&gt;TortoiseHg has an option called “Push New Branch” which we will use from both teams repositories.&amp;#160; As the name implies, it pushes named branches to the central repo.&amp;#160; This is important as we want to be able to see what the other teams are working on without pulling changesets directly from one of the team members.&amp;#160; This is also important for Continuous Integration.&amp;#160; We want each team to have a continuous build for their feature.&amp;#160; This means we want their changes to be able to be pushed to the server’s copy of the repository.&amp;#160; The CI is essentially setup to build all named branches.&amp;#160; &lt;/p&gt;&lt;p&gt;Here is the updated workflow after a few changes from each team have been pushed to the central repo.&amp;#160; &lt;em&gt;*note that a central repo could be a codeplex or bitbucket account but in our case is just a locally hosted mercurial server&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicnUPi4E-FHggAJVCWBzuohMIWbIDkFSq9l-_tetFH0R-GMEOECjD5xK_3q-_PoFJGiBb6g1z3Aw2Rq2nyxY8WQUkFwEFKbkUIzPRM16RW1qKfdpXjlTR2XCR1ytii_3aRY6f5kTk_qs2q/s1600-h/image7.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqPblHg0xbbgqvYATJgPLwuoxa6lktpl4Zyo5aJQNRDWH9vscvXfMP4KcCzP6JU3tFP_4CQSh-rpaXW_VAnTtaT55Bw5Z23ZohtAjPc6ROBmDrnbKb2HuKEkkjhiTQJta4k_chsEP_HUO6/?imgmax=800&quot; width=&quot;779&quot; height=&quot;173&quot; /&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;As you can clearly see, you have two distinct branches coming from the same origin.&amp;#160; You’ll notice we named the branches Bug-1 and Bug-2.&amp;#160; We named the branches this way for bug tracking purposes, you can name your branches however you like.&amp;#160; Let’s say Team2 is done with their feature.&amp;#160; Their next step is to check in their latest changes and &lt;strong&gt;close the branch&lt;/strong&gt;.&amp;#160; This is an important step as mercurial stops tracking closed branches.&amp;#160; This becomes useful in CI scenarios as well, the CI will no longer monitor a closed branch.&amp;#160; You can access the close branch command via the tortoise GUI using the branch button in the commit window. &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV42cuYJK61uoGA3VnBwsWsXTWVhZq85CX-SW105AQ3mCiuvorh41a0DN_Qrb4g_N18zPxDR9jSCSLegM2lEJGPlO7nR3q_qmQ_i0lHHRY3Z9RLhLJK6EEOiPWK1wfGEgOsxX_Sj2SpZEx/s1600-h/image10.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi57-UZdeCTfapG-VG3Eb21fjfGFvIw4p0yc6-EplLDm4qYfozhDzI2qV-ZCZp67bFytuUDrtuVaBjk32Agahj8ph1XKMGvA2lGvDClbRVedYUKU4LbXX2fBap-tlUN33Epe24AeL-bq1dB/?imgmax=800&quot; width=&quot;587&quot; height=&quot;282&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Once the branch is closed and feature is complete, the team can merge the change back into default.&amp;#160; If a team needs to go back to the branch, they can.&amp;#160; Any commits will open the named branch automatically.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQDdsAhjb52yoTBo_ZK2JVvUav_e8x73YxBY2_Fy71WbakIFgXQs-4DlbwPSPDcrYlB-qdgnnXuq2wDQhZsDvrYAj3bqMMYSjwyEIqdfEga4Rmvbb_Ix85Xmul0q04YDadSiMbNNtjwegT/s1600-h/image13.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhssVjMl2rjxegbHsquuMnS__zFzmOqo26gGwkLO3WwCFcMGLS41QhQI-KU2COH1IQHyFlzXrDdingopOWVIBBqMRqXg3gCNaWZfX2RbdotUN7ZQfNUgQ6seCyBA0Hw60tuipX929TKVR7E/?imgmax=800&quot; width=&quot;779&quot; height=&quot;187&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The other team is left finishing their bug and then merging in their changes in the same manner.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioMk420TbL_e888eRXnTmzrXnOV7wUnIoR6cJpKrNtrxHjL2iUhvlHxfObuqQRPMaJzZdiVRdpRIQ0iJlol306PElTdf46cwAX_W4sYTcBAb4Gx_pSAL1AGVIigACe36qHlStL0oVcry3o/s1600-h/image19.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKhcOonmlbDL_8y07MxymJc6SmQMnb21GjS5Ru8vz2FxTiakBbDMbxWGw2JeDxwRKijKMFgOkWNrmxR8cK7Y2Z2OlduST60onwNTMJ3QLRGGxk7OdsOMQ3-l5xF71MNEk7xt5H98qd0AGT/?imgmax=800&quot; width=&quot;785&quot; height=&quot;237&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now your cases are done and your stable branch is ready to be built by your favorite CI and published for the world to see!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Why bother?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;There are many ways to deal with branches in mercurial and this is just the one we settled on.&amp;#160; A lot of people use “branches as clones” or “branching with bookmarks”.&amp;#160; This is a variation on “branching with named branches”.&amp;#160; &lt;a href=&quot;http://stevelosh.com&quot;&gt;Steve Losh&lt;/a&gt; has some great source control posts on his blog and I highly recommend reading them all before making a decision.&lt;/p&gt;&lt;p&gt;There are some of the reasons we chose this workflow&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Organization and Visibility      &lt;ul&gt;&lt;li&gt;It’s easy to look at the list of branches to see what’s being worked on by all contributors.          &lt;ul&gt;&lt;li&gt;If you use bug ids in branch names you can easily search all branches in the future to help find the code your looking for.              &lt;ul&gt;&lt;li&gt;Implicit branches don’t have any identifying markers besides the commit message so it’s hard to find them later when you need them. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;A single clone of the repository means no folder-shuffling between branch switches.          &lt;ul&gt;&lt;li&gt;This is huge for productivity and sanity. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Easily get other contributors involved      &lt;ul&gt;&lt;li&gt;Since the unfinished features aren’t just sitting locally on a developer’s box, you can easily update to any branch and contribute without pulling from a developer’s clone. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Backups      &lt;ul&gt;&lt;li&gt;If you don’t allow force-push and don’t used named branches, backing up the main repo means only getting the main branch code in the backup. &lt;/li&gt;
&lt;li&gt;Developers can constantly push their unfinished branches to the source server and it will get backed up in case of computer failure. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Continuous Integration      &lt;ul&gt;&lt;li&gt;Products like TeamCity allow you to specify a branch name for the build you are setting up, this means each feature branch can have a build.&amp;#160; This would normally be impossible with implicit branches. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Works well with experimental feature branches.      &lt;ul&gt;&lt;li&gt;Just close the branch if it doesn’t work out, no harm no foul. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;You don’t &lt;em&gt;have&lt;/em&gt; to use named branches for everything.&amp;#160; Small html fixes or something can easily be just committed directly to default if needed.       &lt;ul&gt;&lt;li&gt;I highly recommend always using named branches though, they are virtually free and are little trouble for developers.          &lt;ul&gt;&lt;li&gt;We all know how a small feature can turn into a month long project.              &lt;ul&gt;&lt;li&gt;Creating a named branch allows for short term or long-term development with no side affects. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;&lt;font size=&quot;4&quot;&gt;Enforcing the workflow&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The workflow above is great, but mercurial is very flexible and doesn’t enforce such restrictions (rightfully so).&amp;#160; It allows developers to push implicit branches and multiple heads to a repo.&amp;#160; It doesn’t really “allow” it by default, but you can easily use the force push option and end up with a confusing situation for developers.&amp;#160; It even reminds the developer to do so in the error message.&lt;/p&gt;&lt;p&gt;In our case, we want to enforce there there is only a &lt;strong&gt;single head per named branch&lt;/strong&gt;.&amp;#160; For simplicity sake, we will consider default a named branch as well, it’s treated as such in most situations.&amp;#160; This makes things very clear for developers.&amp;#160; You can’t push your changes to the main repo without merging if your teammate has modified the code and beat you to the push.&amp;#160; &lt;/p&gt;&lt;p&gt;Here is the full server plugin we use to enforce this rule.&amp;#160; As you can see, it’s quite simple.&amp;#160; This plugin runs before a push is finished.&amp;#160; So any developer that tries to push a changeset that contains more than one head on any branch would be rejected until the plugin passes the changesets.&amp;#160; Mercurial plugins are a whole topic themselves so I won’t go into how to go about setting it up expect for the bit of notes in the comments from the plugin.&amp;#160; If there is desire for such a tutorial in the future, I’ll write one up on the different ways of setting up mercurial and it’s plugins (client and server).&lt;/p&gt;&lt;pre class=&quot;py&quot; name=&quot;code&quot;&gt;#!/usr/bin/env python

# Enforces that there is only a single head per named branch allowed

# this hooks section should go in the hgrc of the repository you want the rules applied to 
# [hooks] 
# pretxnchangegroup.single_head = python://someserver/location/singlehead.py:single_head

from mercurial.i18n import gettext as _

def single_head(ui, repo, hooktype, node, **kwargs): 
    for b in repo.branchtags():        
        if len(repo.branchheads(b)) &amp;gt; 1: 
            ui.warn(_(&amp;quot;-----------------------------------------\n&amp;quot;)) 
            ui.warn(_(&amp;quot;-----------------------------------------\n&amp;quot;)) 
            ui.warn(_(&amp;quot;Two heads detected on branch &#39;%s&#39;\n&amp;quot; % b)) 
            ui.warn(_(&amp;quot;Only one head per branch is allowed!\n&amp;quot;)) 
            ui.warn(_(&amp;quot;Pull changes, merge and try again\n&amp;quot;)) 
            ui.warn(_(&amp;quot;-----------------------------------------\n&amp;quot;)) 
            ui.warn(_(&amp;quot;-----------------------------------------\n&amp;quot;)) 
            return 1 
    return 0&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/5444760947807009294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/01/mercurial-named-branch-workflow.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5444760947807009294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5444760947807009294'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/01/mercurial-named-branch-workflow.html' title='Mercurial: Named Branch Workflow'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgutHrTlNEhW6s8TxFHvnIPWSk6SLIw2TD0ByRYKs3lymGkmoQ0uDJj0k9ZizYu2eswoB6jsNcDOj_fd7Rt2LQgv3Pomkax8mUVjtWcSqD1AEi0kJOzqS8UTmDGXa_07y2wqkRkF5rp3i6u/s72-c?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-1317577530701982732</id><published>2011-01-20T09:00:00.002-06:00</published><updated>2011-01-20T09:00:01.409-06:00</updated><title type='text'>I’m back to blogging!</title><content type='html'>&lt;p&gt;I&#39;m not dead! Neither is Caleb, though I don&#39;t know if he&#39;ll begin blogging again.&amp;#160; &lt;/p&gt;&lt;p&gt;The lack of new posts here is quite depressing really.&amp;#160; We both left the company we were previously with and moved on to greener pastures and the blogging stopped as we both ramped up at our new gigs.&lt;/p&gt;&lt;p&gt;I&#39;m going try to pump out at least one quality blog post a month and perhaps some smaller posts in between.&amp;#160; I&#39;ve been diving into lots of new technology since I last posted and I&#39;ll try to remember the best bits and put them here.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/1317577530701982732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2011/01/im-back-to-blogging.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1317577530701982732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1317577530701982732'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2011/01/im-back-to-blogging.html' title='I’m back to blogging!'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-932707019125472</id><published>2009-11-05T16:16:00.001-06:00</published><updated>2009-11-05T16:19:48.936-06:00</updated><title type='text'>Simple Silverlight Chat Client Using Sockets</title><content type='html'>&lt;p&gt;This code uses the excellent &lt;a href=&quot;http://socketslight.codeplex.com/&quot;&gt;SocketsLight&lt;/a&gt; library to simplify socket connections in Silverlight.&amp;#160; I’ve put together a simple example of a chat server and client where you can send a message back and forth immediately. &lt;/p&gt;  &lt;p&gt;We plan to extend this idea to integrate with some hardware devices where the console application or Windows service connects to the hardware through drivers then we use sockets to communicate between that application and Silverlight.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;Download&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://drop.io/silverlightsockets&quot;&gt;Download&lt;/a&gt; the example.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;Launching the Server&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Download the project and compile the solution.&amp;#160; &lt;/li&gt;    &lt;li&gt;Run LocalServer\bin\Debug\LocalServer.exe.&amp;#160; This is the console application that the Silverlight application connects to via sockets.&amp;#160; (Run this exe manually so you can F5 debug the Silverlight application.&amp;#160; You can’t debug both of them at the same time). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_V3XTXk73lsMQtUb0SneDnYymOqEJuZz7hQzx1-FPF_3AEWwpTwoYzpKcTfgaTbHec90ms2Q9_cDD9tJp8BV463zWzjF3aN286zqy1SrSeSRhSuy26TybAXRFXz7RxG7oozYPfTAMFnar/s1600-h/image%5B5%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPmYAsvOx29YnTDS7HMzFkIo4BD9QEOFDyZ_hw0aPqQLV_hFX87R-9Um9twgMtYClYMDoyXgMjFfPzZy0mTNR2OLCDIRUiprrnfoVbWa1wWzGOBUA5Nysmw2IQVDo3um6RvQLlmMfpe-g7/?imgmax=800&quot; width=&quot;600&quot; height=&quot;316&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;Launching the Silverlight application&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Set the SilverlightSockets.Web project as the startup project and run. &lt;/li&gt;    &lt;li&gt;You should a message saying that the connection to the server succeeded. &lt;/li&gt;    &lt;li&gt;Type in a message and verify that the message appears on the server. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcX18SmDaVh3cZ1V6pxijxRTqw3IpDiP4EBSWmKJnl3xuv9y-6w5Gy6Vz8xbTDuSVyoYKS2lmi8gxNAUomYkYPmRpLwUCxTY3BILPNfs-rUbEJNJRrfWBh4XXIZ1tBtPalf9CLTK0HGk_h/s1600-h/image%5B11%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE1doASzaRTq9_QKtZJq4UjFCtNn3Sx9ZVsvuAcI5qqsJ2wrXdpFuIRlYzMPMqwu-rSXghWWoO_zp4xefBOqbqNQXqkhXn4nyh3NTNsdUyYWf8_E9G9oTZKROA4m2JDffF9ADsyEUzyiZ7/?imgmax=800&quot; width=&quot;439&quot; height=&quot;269&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Now you can type messages on the Silverlight client and on the server.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;Console application (LocalServer.exe)&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;This is the console application that the Silverlight client connects to.&amp;#160; The PolicyServer and MessageServer classes are included in the &lt;a href=&quot;http://socketslight.codeplex.com/&quot;&gt;SocketsLight&lt;/a&gt; library, and provide a simple event driven model for dealing with sockets.&amp;#160; The PolicyServer is just a simple web server that accepts requests to &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc645032%28VS.95%29.aspx&quot;&gt;clientaccesspolicy.xml&lt;/a&gt;, which is necessary to use sockets in Silverlight.&lt;/p&gt;  &lt;p&gt;TextMessage is a class that I defined on both the server and the Silverlight client.&amp;#160; This stores data that’s sent over the wire in both directions.&lt;/p&gt;  &lt;p&gt;In this example, I’m firing up the PolicyServer and MessageServer on different threads and reading in any input typed in by the user.&lt;/p&gt;  &lt;p&gt;When a client connects, the ClientStatusChangedEventArgs contains a GUID that uniquely identifies the connection.&amp;#160; You use this GUID when you want to send a message to the client.&amp;#160; This example just supports a single connection, but you can easily keep track of the GUIDs for the different collections to support multiple connections.&lt;/p&gt;  &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;class Program
{
    private static Guid _clientID = Guid.Empty;

    private static bool IsConnected
    {
        get { return _clientID != Guid.Empty; }
    }

    static void Main(string[] args)
    {
        var policyServer = new PolicyServer(&amp;quot;../../clientaccesspolicy.xml&amp;quot;);
        IMessageServer messageServer = new MessageServer(
            IPAddress.Any,
            4530,
            new JsonMessageSerializer(new List&amp;lt;Type&amp;gt;() { typeof(TextMessage) }));

        messageServer.ClientConnected += new EventHandler&amp;lt;ClientStatusChangedEventArgs&amp;gt;(messageServer_ClientConnected);
        messageServer.ClientDisconnected += new EventHandler&amp;lt;ClientStatusChangedEventArgs&amp;gt;(messageServer_ClientDisconnected);

        ThreadPool.QueueUserWorkItem((o) =&amp;gt; { policyServer.Start(); });
        ThreadPool.QueueUserWorkItem((o) =&amp;gt; { messageServer.Start(); });

        var textService = new TextService(messageServer);

        // Wait for messages to be typed and send to client.
        while (true)
        {
            string input = Console.ReadLine();
            if (IsConnected)
            {
                messageServer.SendMessageToClient(_clientID, new TextMessage { Text = input });
            }
            else
            {
                Console.WriteLine(&amp;quot;Warning: there are not clients connected to receive the message.&amp;quot;);
            }
        }
    }

    static void messageServer_ClientDisconnected(object sender, ClientStatusChangedEventArgs e)
    {
        _clientID = Guid.Empty;
        Console.WriteLine(&amp;quot;Connection closed for &amp;quot; + e.ClientId);
    }

    static void messageServer_ClientConnected(object sender, ClientStatusChangedEventArgs e)
    {
        _clientID = e.ClientId;
        Console.WriteLine(&amp;quot;Connection opened for &amp;quot; + e.ClientId);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;TextService.cs (runs on the console application)&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;The data contract I defined between the server and client. It needs to inherit from the Message class included in the SocketsLight library. &lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;namespace LocalServer
{
    using Witcraft.SocketsLight.Server;
    using System.Runtime.Serialization;
    
    [DataContract]
    public class TextMessage : Message
    {
        [DataMember]
        public string Text { get; set; }
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;TextService.cs (runs on the console application)&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public class TextService
{
    private IMessageServer _messageServer;
    Guid _clientID = Guid.Empty;

    public bool IsConnected
    {
        get { return _clientID != Guid.Empty; }
    }

    public TextService(IMessageServer messageServer)
    {
        _messageServer = messageServer;
        _messageServer.ClientConnected += new EventHandler&amp;lt;ClientStatusChangedEventArgs&amp;gt;(_messageServer_ClientConnected);
        _messageServer.ClientDisconnected += new EventHandler&amp;lt;ClientStatusChangedEventArgs&amp;gt;(_messageServer_ClientDisconnected);
        _messageServer.MessageRecieved += new EventHandler&amp;lt;MessageRecievedEventArgs&amp;gt;(_messageServer_MessageRecieved);
    }

    void _messageServer_MessageRecieved(object sender, MessageRecievedEventArgs e)
    {
        if (IsConnected)
        {
            TextMessage message = e.Message as TextMessage;
            if (message != null)
            {
                Console.WriteLine(&amp;quot;Message Received: &amp;quot; + message.Text);
            }
        }
    }

    void _messageServer_ClientDisconnected(object sender, ClientStatusChangedEventArgs e)
    {
        _clientID = Guid.Empty;
    }

    void _messageServer_ClientConnected(object sender, ClientStatusChangedEventArgs e)
    {
        _clientID = e.ClientId;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Code-behind for Silverlight UserControl&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public partial class MainPage : UserControl
{
    const int TCP_PORT = 4530;
    IMessageClient _messageClient;

    public MainPage()
    {
        InitializeComponent();
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        _messageClient = new MessageClient
        (
            TCP_PORT,
            new JsonMessageSerializer(new List&amp;lt;Type&amp;gt;() { typeof(TextMessage) })
        );
        _messageClient.MessageRecieved += 
            new EventHandler&amp;lt;MessageRecievedEventArgs&amp;gt;(_messageClient_MessageRecieved);
        _messageClient.ConnectCompleted += 
            new EventHandler&amp;lt;AsyncCompletedEventArgs&amp;gt;(
                _messageClient_ConnectCompleted);
        _messageClient.ConnectAsync();

        AddMessage(&amp;quot;System&amp;quot;, &amp;quot;Trying to connect on TCP port &amp;quot; + TCP_PORT + &amp;quot;...&amp;quot;);

        SendText.Focus();
    }        

    void _messageClient_ConnectCompleted(object sender, AsyncCompletedEventArgs e)
    {
        AddMessage(&amp;quot;System&amp;quot;, &amp;quot;Connected!&amp;quot;);
        this.Dispatcher.BeginInvoke(() =&amp;gt; this.SendButton.IsEnabled = true );
    }

    void _messageClient_MessageRecieved(object sender, MessageRecievedEventArgs e)
    {
        TextMessage message = e.Message as TextMessage;
        if (message != null)
            AddMessage(&amp;quot;Server&amp;quot;, message.Text);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        SendMessage();
    }

    private void SendText_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
            SendMessage();
    }

    private void SendMessage()
    {
        AddMessage(&amp;quot;Me&amp;quot;, SendText.Text);
        _messageClient.SendMessageAsync(new TextMessage { Text = SendText.Text });
        SendText.Text = string.Empty;
    }

    // Updates UI with messages sent/received.
    private void AddMessage(string sender, string message)
    {
        this.Dispatcher.BeginInvoke
        (() =&amp;gt;
            {
                this.Received.Text += string.Format(&amp;quot;{0}: {1}&amp;quot;, sender, message) + Environment.NewLine;
                this.Scroller.UpdateLayout();
                this.Scroller.ScrollToVerticalOffset(double.MaxValue);
            }
        );
    }        
}&lt;/pre&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/932707019125472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/11/simple-silverlight-chat-client-using.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/932707019125472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/932707019125472'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/11/simple-silverlight-chat-client-using.html' title='Simple Silverlight Chat Client Using Sockets'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPmYAsvOx29YnTDS7HMzFkIo4BD9QEOFDyZ_hw0aPqQLV_hFX87R-9Um9twgMtYClYMDoyXgMjFfPzZy0mTNR2OLCDIRUiprrnfoVbWa1wWzGOBUA5Nysmw2IQVDo3um6RvQLlmMfpe-g7/s72-c?imgmax=800" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-7780125228861588900</id><published>2009-09-01T13:39:00.001-05:00</published><updated>2009-09-01T13:41:07.460-05:00</updated><title type='text'>To Return Early or Not From a Method?</title><content type='html'>&lt;p&gt;I remember always being told to not return early from a method.&amp;#160; However, I think it makes sense in some cases when you would otherwise have a set of nested “if” statements.&lt;/p&gt;  &lt;p&gt;Take this example I ran across while working in our production system:&lt;/p&gt;  &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;private void GetDiscountCode(Registration registration, Registrant registrant)
{
    if (registration.EventProfile.DiscountCodesEnabled &amp;amp;&amp;amp;
        registration.EventProfile.DiscountCodes.Count &amp;gt; 0)
    {
        if (tbDiscountCode.Text.Trim() != string.Empty)
        {
            DiscountCode discountCode = registration.EventProfile.DiscountCodes.Find(tbDiscountCode.Text);
            if (discountCode != null)
            {
                if (discountCode.Active)
                {
                    if (!discountCode.Limited
                        || discountCode.DiscountsUsed &amp;lt; discountCode.MaximumAllowed)
                    {
                        if (registrant.DiscountCodeApplied != discountCode.DiscountCodeId)
                        {
                            if (registrant.DiscountCodePercentage &amp;lt;= discountCode.DiscountPercentage)
                            {
                                registrant.DiscountCodeApplied = discountCode.DiscountCodeId;
                                registrant.DiscountCodePercentage = discountCode.DiscountPercentage;
                                registrant.DiscountCodeAmountPerLineItem = discountCode.DiscountAmount;
                                
                            }
                        }
                    }
                    else
                    {
                        errorMessages.Add(string.Format(&amp;quot;The {0} you entered is no longer available&amp;quot;, registration.EventProfile.DiscountCodeLabel));
                    }
                }
                else
                {
                    errorMessages.Add(string.Format(&amp;quot;The {0} you entered is not currently active&amp;quot;, registration.EventProfile.DiscountCodeLabel));
                }
            }
            else
            {
                errorMessages.Add(string.Format(&amp;quot;The {0} you entered is not valid for this event&amp;quot;, registration.EventProfile.DiscountCodeLabel));
            }
        }
        else
        {
            registrant.DiscountCodeApplied = -1;
            registrant.DiscountCodePercentage = 0;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;After refactoring (with the same behavior):&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;private void GetDiscountCode(Registration registration, Registrant registrant)
{
    if (!registration.EventProfile.DiscountCodesEnabled ||
        registration.EventProfile.DiscountCodes.Count == 0)
        return;

    string codeText = tbDiscountCode.Text.Trim();
    if (codeText == string.Empty)
    {
        registrant.DiscountCodeApplied = -1;
        registrant.DiscountCodePercentage = 0;
        registrant.DiscountCodeAmountPerLineItem = 0;
        return;
    }

    DiscountCode discountCode = registration.EventProfile.DiscountCodes.Find(codeText);
    if (discountCode == null)
    {
        errorMessages.Add(string.Format(&amp;quot;The {0} you entered is not valid for this event&amp;quot;,
            registration.EventProfile.DiscountCodeLabel));
        return;
    }

    if (!discountCode.Active)
    {
        errorMessages.Add(string.Format(&amp;quot;The {0} you entered is no longer available&amp;quot;,
            registration.EventProfile.DiscountCodeLabel));
        return;
    }

    if (discountCode.Limited &amp;amp;&amp;amp; (discountCode.DiscountsUsed &amp;gt;= discountCode.MaximumAllowed))
    {
        errorMessages.Add(string.Format(&amp;quot;The {0} you entered is no longer available&amp;quot;,
            registration.EventProfile.DiscountCodeLabel));
        return;
    }

    if (registrant.DiscountCodeApplied != discountCode.DiscountCodeId)
    {
        if (registrant.DiscountCodePercentage &amp;lt;= discountCode.DiscountPercentage)
        {
            registrant.DiscountCodeApplied = discountCode.DiscountCodeId;
            registrant.DiscountCodePercentage = discountCode.DiscountPercentage;
            registrant.DiscountCodeAmountPerLineItem = discountCode.DiscountAmount;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;I tend to think the refactored code is easier to read and maintain.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/7780125228861588900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/09/to-return-early-or-not-from-method.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7780125228861588900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7780125228861588900'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/09/to-return-early-or-not-from-method.html' title='To Return Early or Not From a Method?'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-1791871708712753060</id><published>2009-08-14T13:21:00.001-05:00</published><updated>2009-08-14T13:21:58.213-05:00</updated><title type='text'>Mutually Exclusive HTML Select Elements Using jQuery</title><content type='html'>&lt;p&gt;This jQuery code snippet shows how to make a number of related html select elements mutually exclusive.&amp;#160; That is, all of the select elements have the same list of options, but you should only be allowed to choose a given option once.&lt;/p&gt;  &lt;p&gt;In this example, you’re given a list of books to choose.&amp;#160; Every time you choose a book, it disables that book and crosses it out so the user knows it’s already been used and can’t select it again.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ1kCj2ZVfbE290KQ-AcXLua5fXpyGK5hgaRhmwTb1GHErXMCbEMScw_0Ro999eUq3AKZ4btkFVwG0jH5pWql2cS88daGeEpNITL6m9UZ3nyBzfad81FfN2606IMj-HD5UeI91lRsTqSyo/s1600-h/image%5B5%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTzdYe8ObyHxFLAapajZVeA3Pf5oRWTxfqo3g4Iq_MFH3_fDAg0vuV53rmI9HPzxPPwZdPVFfn5iyRyKuamHmi4Si0PCVUqLfTtEA17VAfanl5wKrBqN93PPv4h6qBEcexxGczcGaXIMpU/?imgmax=800&quot; width=&quot;267&quot; height=&quot;323&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here’s the code:&lt;/p&gt;  &lt;p&gt;&lt;u&gt;&lt;strong&gt;Example Markup&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;p&amp;gt;
Book 1:
&amp;lt;select id=&amp;quot;book_1&amp;quot;&amp;gt;
    &amp;lt;option value=&amp;quot;&amp;quot;&amp;gt;-Select One-&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;1&amp;quot;&amp;gt;Atlas Shrugged&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;2&amp;quot;&amp;gt;Brave New World&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;3&amp;quot;&amp;gt;Brothers Karamazov&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;4&amp;quot;&amp;gt;Call of the Wild&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;5&amp;quot;&amp;gt;For Whom the Bell Tolls&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;6&amp;quot;&amp;gt;Lord of the Flies&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;7&amp;quot;&amp;gt;The Catcher in the Rye&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;8&amp;quot;&amp;gt;The Grapes of Wrath&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;9&amp;quot;&amp;gt;The Great Gatsby&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;10&amp;quot;&amp;gt;The Picture of Dorian Gray&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;11&amp;quot;&amp;gt;The Prince&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;12&amp;quot;&amp;gt;The Wealth of Nations&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;
Book 2:
&amp;lt;select id=&amp;quot;book_2&amp;quot;&amp;gt;
    &amp;lt;option value=&amp;quot;&amp;quot;&amp;gt;-Select One-&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;1&amp;quot;&amp;gt;Atlas Shrugged&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;2&amp;quot;&amp;gt;Brave New World&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;3&amp;quot;&amp;gt;Brothers Karamazov&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;4&amp;quot;&amp;gt;Call of the Wild&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;5&amp;quot;&amp;gt;For Whom the Bell Tolls&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;6&amp;quot;&amp;gt;Lord of the Flies&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;7&amp;quot;&amp;gt;The Catcher in the Rye&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;8&amp;quot;&amp;gt;The Grapes of Wrath&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;9&amp;quot;&amp;gt;The Great Gatsby&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;10&amp;quot;&amp;gt;The Picture of Dorian Gray&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;11&amp;quot;&amp;gt;The Prince&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;12&amp;quot;&amp;gt;The Wealth of Nations&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;
Book 3:
&amp;lt;select id=&amp;quot;book_3&amp;quot;&amp;gt;
    &amp;lt;option value=&amp;quot;&amp;quot;&amp;gt;-Select One-&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;1&amp;quot;&amp;gt;Atlas Shrugged&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;2&amp;quot;&amp;gt;Brave New World&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;3&amp;quot;&amp;gt;Brothers Karamazov&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;4&amp;quot;&amp;gt;Call of the Wild&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;5&amp;quot;&amp;gt;For Whom the Bell Tolls&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;6&amp;quot;&amp;gt;Lord of the Flies&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;7&amp;quot;&amp;gt;The Catcher in the Rye&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;8&amp;quot;&amp;gt;The Grapes of Wrath&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;9&amp;quot;&amp;gt;The Great Gatsby&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;10&amp;quot;&amp;gt;The Picture of Dorian Gray&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;11&amp;quot;&amp;gt;The Prince&amp;lt;/option&amp;gt;
    &amp;lt;option value=&amp;quot;12&amp;quot;&amp;gt;The Wealth of Nations&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(function(){
    $(&#39;select[id^=book_]&#39;).change(function()
    {
        // List of ids that are selected in all select elements
        var selected = new Array();
        
        // Get a list of the ids that are selected
        $(&#39;[id^=book_] option:selected&#39;).each(function()
        {
            selected.push($(this).val());
        });
        
        // Walk through every select option and enable if not 
        // in the list and not already selected
        $(&#39;[id^=book_] option&#39;).each(function()
        {
            if (!$(this).is(&#39;:selected&#39;) &amp;amp;&amp;amp; $(this).val() != &#39;&#39;)
            {
                var shouldDisable = false;
                for (var i = 0; i &amp;lt; selected.length; i++)
                {
                    if (selected[i] == $(this).val())
                        shouldDisable = true;
                }
                
                $(this).css(&#39;text-decoration&#39;, &#39;&#39;);
                $(this).removeAttr(&#39;disabled&#39;, &#39;disabled&#39;);
                if (shouldDisable)
                {
                    $(this).css(&#39;text-decoration&#39;, &#39;line-through&#39;);
                    $(this).attr(&#39;disabled&#39;, &#39;disabled&#39;);
                }
            }
        });
    });
});&lt;/pre&gt;

&lt;p&gt;Note: IE, of course, doesn’t support &amp;lt;option disabled=”disabled” /&amp;gt;, so it will only change the font to strike through.&amp;#160; You’ll need to add some validation to make sure a value isn’t chosen multiple times if you plan to support IE.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/1791871708712753060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/08/mutually-exclusive-html-select-elements.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1791871708712753060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1791871708712753060'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/08/mutually-exclusive-html-select-elements.html' title='Mutually Exclusive HTML Select Elements Using jQuery'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTzdYe8ObyHxFLAapajZVeA3Pf5oRWTxfqo3g4Iq_MFH3_fDAg0vuV53rmI9HPzxPPwZdPVFfn5iyRyKuamHmi4Si0PCVUqLfTtEA17VAfanl5wKrBqN93PPv4h6qBEcexxGczcGaXIMpU/s72-c?imgmax=800" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-3412310711599587036</id><published>2009-08-07T09:06:00.005-05:00</published><updated>2009-08-07T09:58:39.302-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type='text'>Generic Query String Helper for ASP.NET</title><content type='html'>&lt;p&gt;Query strings are something we deal with constantly.&amp;#160; I’ve come up with a helper that uses .NET Generics to handle a lot of common cases that we usually write unnecessary code for.&lt;/p&gt;  &lt;p&gt;Example Usage:&lt;/p&gt;  &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;// Required.  Will throw exceptions if the query string value is null or empty string.
int personID = QS.Value&amp;lt;int&amp;gt;(&amp;quot;personID&amp;quot;);
string keywords = QS.Value&amp;lt;string&amp;gt;(&amp;quot;keywords&amp;quot;);
// Optional.  Use default value if query string value is null or empty.
int startIndex = QS.Value&amp;lt;int&amp;gt;(&amp;quot;startIndex&amp;quot;, 0);&lt;/pre&gt;

&lt;p&gt;This is short hand for writing:&lt;/p&gt;

&lt;pre style=&quot;overflow-x: auto&quot; class=&quot;c#&quot; name=&quot;code&quot;&gt;int personID;
if (string.IsNullOrEmpty(Request.QueryString[&amp;quot;personID&amp;quot;]))
    throw new InvalidOperationException(&amp;quot;Expected the personID query string parameter to exist&amp;quot;);
if (!int.TryParse(Request.QueryString[&amp;quot;personID&amp;quot;], out personID))
    throw new InvalidOperationException(string.Format(&amp;quot;Unable to convert query string parameter named &#39;personID&#39; with value of &#39;{0}&#39; to type int&amp;quot;, Request.QueryString[&amp;quot;personID&amp;quot;]));

string keywords = Request.QueryString[&amp;quot;keywords&amp;quot;];
if (string.IsNullOrEmpty(keywords))
    throw new InvalidOperationException(&amp;quot;Expected the keywords query string parameter to exist&amp;quot;);

int startIndex;
if (string.IsNullOrEmpty(Request.QueryString[&amp;quot;startIndex&amp;quot;]))
    startIndex = 0;
else if (!int.TryParse(Request.QueryString[&amp;quot;startIndex&amp;quot;], out startIndex))
    throw new InvalidOperationException(string.Format(&amp;quot;Unable to convert query string parameter named &#39;startIndex&#39; with value of &#39;{0}&#39; to type int&amp;quot;, Request.QueryString[&amp;quot;startIndex&amp;quot;]));&lt;/pre&gt;

&lt;p&gt;Here’s the source code for the query string helper class:&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public class QS
{
    public static T Value&amp;lt;T&amp;gt;(string parameterName) where T : IConvertible
    {
        if (HttpContext.Current == null)
            throw new InvalidOperationException(&amp;quot;Cannot call QS&amp;lt;T&amp;gt; when HttpContext.Current is null&amp;quot;);

        if (string.IsNullOrEmpty(HttpContext.Current.Request[parameterName]))
            throw new InvalidOperationException(string.Format(&amp;quot;Expected query string parameter named &#39;{0}&#39; to exist&amp;quot;, parameterName));

        return Value&amp;lt;T&amp;gt;(parameterName, default(T));
    }

    public static T Value&amp;lt;T&amp;gt;(string parameterName, T defaultValue) where T : IConvertible
    {
        if (HttpContext.Current == null)
            throw new InvalidOperationException(&amp;quot;Cannot call QS&amp;lt;T&amp;gt; when HttpContext.Current is null&amp;quot;);

        HttpRequest request = HttpContext.Current.Request;

        string input;
        if (request.QueryString[parameterName] != null &amp;amp;&amp;amp; !string.IsNullOrEmpty(request.QueryString[parameterName]))
            input = request.QueryString[parameterName];
        else
            return defaultValue;

        T value;
        try
        {
            value = (T)Convert.ChangeType(input, typeof(T));
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(string.Format(&amp;quot;Unable to convert query string parameter named &#39;{0}&#39; with value of &#39;{1}&#39; to type {2}&amp;quot;, parameterName, input, typeof(T).FullName), ex);
        }
        return value;
    }
}&lt;/pre&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/3412310711599587036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/08/generic-query-string-helper-for-aspnet.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3412310711599587036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3412310711599587036'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/08/generic-query-string-helper-for-aspnet.html' title='Generic Query String Helper for ASP.NET'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-1081846494919922976</id><published>2009-07-13T08:38:00.001-05:00</published><updated>2009-07-13T08:38:42.140-05:00</updated><title type='text'>Iterating a Complex DataList Hierarchy With Custom Iterators</title><content type='html'>&lt;p&gt;This is a follow-up post to &lt;a href=&quot;http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy.html&quot;&gt;Iterating a Complex DataList Hierarchy With Lambda Expressions&lt;/a&gt;, which showed one way to avoid code duplication when iterating a complex control hierarchy.&amp;#160; This shows how to achieve roughly the same thing by taking advantage of the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/9k7k7cf0%28VS.80%29.aspx&quot;&gt;yield&lt;/a&gt; keyword.&lt;/p&gt;  &lt;p&gt;Again, here’s the DataList we need to traverse (see the &lt;a href=&quot;http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy.html&quot;&gt;original post&lt;/a&gt; for more details on what the demo does).&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;asp:DataList ID=&amp;quot;dlFamilies&amp;quot; runat=&amp;quot;server&amp;quot; DataKeyField=&amp;quot;FamilyID&amp;quot;&amp;gt;
    &amp;lt;ItemTemplate&amp;gt;
        &amp;lt;%# Eval(&amp;quot;FamilyName&amp;quot;) %&amp;gt;
        &amp;lt;asp:DataList ID=&amp;quot;dlPeople&amp;quot; runat=&amp;quot;server&amp;quot; DataSource=&#39;&amp;lt;%# Eval(&amp;quot;FamilyMembers&amp;quot;) %&amp;gt;&#39; &lt;br /&gt;            DataKeyField=&amp;quot;PersonID&amp;quot;&amp;gt;
            &amp;lt;ItemTemplate&amp;gt;
                &amp;lt;asp:CheckBox 
                    CssClass=&amp;quot;person-checkbox&amp;quot; 
                    ID=&amp;quot;cbPerson&amp;quot; 
                    runat=&amp;quot;server&amp;quot; 
                    Text=&#39;&amp;lt;%# Eval(&amp;quot;Name&amp;quot;) + &amp;quot; (&amp;quot; + Eval(&amp;quot;Gender&amp;quot;) + &amp;quot;)&amp;quot; %&amp;gt;&#39;
                    AutoPostBack=&amp;quot;true&amp;quot;
                    OnCheckedChanged=&amp;quot;cbPerson_CheckedChanged&amp;quot;
                 /&amp;gt;
            &amp;lt;/ItemTemplate&amp;gt;
        &amp;lt;/asp:DataList&amp;gt;
    &amp;lt;/ItemTemplate&amp;gt;
&amp;lt;/asp:DataList&amp;gt;&lt;/pre&gt;

&lt;p&gt;This boiler plate code might be copied multiple times to perform whatever action you need on the data.&lt;/p&gt;

&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;// Loop through DataList that shows families.
foreach (DataListItem familyItem in dlFamilies.Items)
{
    // Find family object based on FamilyID
    int currentFamilyID = (int)dlFamilies.DataKeys[familyItem.ItemIndex];
    Family family = _families.Where(f =&amp;gt; f.FamilyID == currentFamilyID).FirstOrDefault();

    // Grab the inner DataList that shows people in a family.
    DataList dlPeople = (DataList)familyItem.FindControl(&amp;quot;dlPeople&amp;quot;);
    foreach (DataListItem personItem in dlPeople.Items)
    {
        // Find person object based on PersonID
        int currentPersonID = (int)dlPeople.DataKeys[personItem.ItemIndex];
        Person person = family.FamilyMembers.Where(p =&amp;gt; p.PersonID == currentPersonID).FirstOrDefault();

        // DO SOMETHING
    }
}&lt;/pre&gt;

&lt;p&gt;Instead of duplicating this code, we create a custom iterator that returns a PersonRow object for every person in the DataList.&amp;#160; It includes a strongly typed reference to the Person, Family, and a boolean telling you whether or not the checkbox is checked.&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;private IEnumerable&amp;lt;PersonRow&amp;gt; GetPeople()
{
    // Loop through DataList that shows families.
    foreach (DataListItem familyItem in dlFamilies.Items)
    {
        // Find family object based on FamilyID
        int currentFamilyID = (int)dlFamilies.DataKeys[familyItem.ItemIndex];
        Family family = _families.Where(f =&amp;gt; f.FamilyID == currentFamilyID).FirstOrDefault();

        // Grab the inner DataList that shows people in a family.
        DataList dlPeople = (DataList)familyItem.FindControl(&amp;quot;dlPeople&amp;quot;);
        foreach (DataListItem personItem in dlPeople.Items)
        {
            // Find person object based on PersonID
            int currentPersonID = (int)dlPeople.DataKeys[personItem.ItemIndex];
            Person person = family.FamilyMembers.Where(p =&amp;gt; p.PersonID == currentPersonID).FirstOrDefault();

            CheckBox cb = (CheckBox)personItem.FindControl(&amp;quot;cbPerson&amp;quot;);

            PersonRow row = new PersonRow { Family = family, Person = person, Selected = cb.Checked };
            yield return row;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;One advantage of using yield instead of a lambda expression is that the code is more readable.&amp;#160; You just loop through a collection.&amp;#160; A disadvantage is that you need to create a custom class to hold the result of your iterator.&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public class PersonRow
{
    public Person Person { get; set; }
    public Family Family { get; set; }
    public bool Selected { get; set; }
}&lt;/pre&gt;

&lt;p&gt;Here’s code that uses the new iterator:&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;// Called when a checkbox is checked.
protected void cbPerson_CheckedChanged(object sender, EventArgs e)
{
    int maleCount = GetPeople()
        .Where(r =&amp;gt; r.Person.Gender == Gender.Male &amp;amp;&amp;amp; r.Selected)
        .Count();
    
    int femaleCount = GetPeople()
        .Where(r =&amp;gt; r.Person.Gender == Gender.Female &amp;amp;&amp;amp; r.Selected)
        .Count();

    btnGetPeople.Enabled = 
        maleCount == REQUIRED_MALE_COUNT &amp;amp;&amp;amp;
        femaleCount == REQUIRED_FEMALE_COUNT;

    lblState.Text = string.Format(&amp;quot;{0} male(s) selected and {1} females selected&amp;quot;,
        maleCount,
        femaleCount);
}&lt;/pre&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;// Caled when the submit button is pressed
protected void btnGetPeople_Click(object sender, EventArgs e)
{
    lblSelectedPeople.Text = string.Empty;

    foreach (PersonRow row in GetPeople().Where(p =&amp;gt; p.Selected).ToList())
    {
        lblSelectedPeople.Text += row.Person.ToString() + &amp;quot;&amp;lt;br /&amp;gt;&amp;quot;;
    }
}&lt;/pre&gt;
I’ve included an updated sample available for &lt;a href=&quot;http://drop.io/iteratedatalistyield/asset/datalistiteratortest-yield-zip&quot;&gt;download&lt;/a&gt;. 

  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/1081846494919922976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy_13.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1081846494919922976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1081846494919922976'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy_13.html' title='Iterating a Complex DataList Hierarchy With Custom Iterators'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-1622299094870429155</id><published>2009-07-09T10:51:00.001-05:00</published><updated>2009-07-13T08:40:52.927-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type='text'>Iterating a Complex DataList Hierarchy With Lambda Expressions</title><content type='html'>&lt;p style=&quot;background-color: #E3E3E3&quot;&gt;Update: I’ve added a &lt;a href=&quot;http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy_13.html&quot;&gt;new blog post&lt;/a&gt; on how to do the same thing with a custom iterator using the yield keyword.&lt;/p&gt;  &lt;p&gt;This post demonstrates one way to use lambda expressions as part of a strategy to avoid code duplication when iterating over complex control hierarchies.&lt;/p&gt;  &lt;p&gt;For example, if you have nested DataLists and you need to loop over the DataList to perform different actions, you might be tempted to copy and paste the code to perform whichever action you need to do.&lt;/p&gt;  &lt;p&gt;In this made-up and useless example, we have a list of families and family members.&amp;#160; You must choose a certain number of males and females then press the Submit button to get a list of the selected people.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-RN6aEa-B6L5ZFIaYBClDKd8ZlhqTAI3ZIg8YSNM7bwci-KMFbSH7AhQZd3a97KU1AW2bS4YJdkew_Zlmorw68guuT5iXUJ7YzkxneOazztYsP0JVCfCdDDVT1CiY5Lu3WXIHkuuX19bu/s1600-h/image%5B12%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXu9e4R7eJ1uT8PmfKG3ymUWPCWhotbKllw2HhKJ9Z5Odlvza2YFQGgMlzBOyXl7BCPiJadW6Bq0Jc2PCrveSBJAalGv4Im4TrJx5Y8wVi_fmQUnookQvzsyNGDNaU1BcrYagUbMQrn7iX/?imgmax=800&quot; width=&quot;259&quot; height=&quot;390&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-B95Tr_I3b0ysJEocyGmbnjuwWrHterr-5qshiuSCcVoIG2R9Srb_tmXnrqZ58ZzdDwDu8dRvZsT9dyjvK3IORfIHBM_9OHYMhKM194TXJr5Bb4ZpXZ3p6gGJiBKT85GDtXrK1KnQQfLq/s1600-h/image%5B7%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM0QYbz9z1bfEUO4AVcCBiF2adZgJAl7yVR9ebsrB7qkgywRD0Yhn6Bc-MaGTAjemZozREUQhs6_xiCVSnw0IebXrBHyqF2tgXjW5DOv2Sy6OVzetWdknqpOothJi-BLMfECuFJlAxWndA/?imgmax=800&quot; width=&quot;261&quot; height=&quot;390&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;asp:DataList ID=&amp;quot;dlFamilies&amp;quot; runat=&amp;quot;server&amp;quot; DataKeyField=&amp;quot;FamilyID&amp;quot;&amp;gt;
    &amp;lt;ItemTemplate&amp;gt;
        &amp;lt;%# Eval(&amp;quot;FamilyName&amp;quot;) %&amp;gt;
        &amp;lt;asp:DataList ID=&amp;quot;dlPeople&amp;quot; runat=&amp;quot;server&amp;quot; DataSource=&#39;&amp;lt;%# Eval(&amp;quot;FamilyMembers&amp;quot;) %&amp;gt;&#39; &lt;br /&gt;            DataKeyField=&amp;quot;PersonID&amp;quot;&amp;gt;
            &amp;lt;ItemTemplate&amp;gt;
                &amp;lt;asp:CheckBox 
                    CssClass=&amp;quot;person-checkbox&amp;quot; 
                    ID=&amp;quot;cbPerson&amp;quot; 
                    runat=&amp;quot;server&amp;quot; 
                    Text=&#39;&amp;lt;%# Eval(&amp;quot;Name&amp;quot;) + &amp;quot; (&amp;quot; + Eval(&amp;quot;Gender&amp;quot;) + &amp;quot;)&amp;quot; %&amp;gt;&#39;
                    AutoPostBack=&amp;quot;true&amp;quot;
                    OnCheckedChanged=&amp;quot;cbPerson_CheckedChanged&amp;quot;
                 /&amp;gt;
            &amp;lt;/ItemTemplate&amp;gt;
        &amp;lt;/asp:DataList&amp;gt;
    &amp;lt;/ItemTemplate&amp;gt;
&amp;lt;/asp:DataList&amp;gt;&lt;/pre&gt;

&lt;p&gt;This boiler plate code might be copied multiple times to perform whatever action you need on the data.&lt;/p&gt;

&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;// Loop through DataList that shows families.
foreach (DataListItem familyItem in dlFamilies.Items)
{
    // Find family object based on FamilyID
    int currentFamilyID = (int)dlFamilies.DataKeys[familyItem.ItemIndex];
    Family family = _families.Where(f =&amp;gt; f.FamilyID == currentFamilyID).FirstOrDefault();

    // Grab the inner DataList that shows people in a family.
    DataList dlPeople = (DataList)familyItem.FindControl(&amp;quot;dlPeople&amp;quot;);
    foreach (DataListItem personItem in dlPeople.Items)
    {
        // Find person object based on PersonID
        int currentPersonID = (int)dlPeople.DataKeys[personItem.ItemIndex];
        Person person = family.FamilyMembers.Where(p =&amp;gt; p.PersonID == currentPersonID).FirstOrDefault();

        // DO SOMETHING
    }
}&lt;/pre&gt;

&lt;p&gt;Instead of duplicating this code, I’d suggest creating a method to iterate over the DataList hierarchy.&amp;#160; You would pass in a delegate to perform whatever action you need on the data.&lt;/p&gt;

&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private void IteratePeople(Action&amp;lt;Person, Family, DataListItem&amp;gt; action)
{
    // Loop through DataList that shows families.
    foreach (DataListItem familyItem in dlFamilies.Items)
    {
        // Find family object based on FamilyID
        int currentFamilyID = (int)dlFamilies.DataKeys[familyItem.ItemIndex];
        Family family = _families.Where(f =&amp;gt; f.FamilyID == currentFamilyID).FirstOrDefault();

        // Grab the inner DataList that shows people in a family.
        DataList dlPeople = (DataList)familyItem.FindControl(&amp;quot;dlPeople&amp;quot;);
        foreach (DataListItem personItem in dlPeople.Items)
        {
            // Find person object based on PersonID
            int currentPersonID = (int)dlPeople.DataKeys[personItem.ItemIndex];
            Person person = family.FamilyMembers.Where(p =&amp;gt; p.PersonID == currentPersonID).FirstOrDefault();

            // Call delegate passed in.
            action(person, family, personItem);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;(Action&amp;lt;T1, T2, T3&amp;gt; is a helper built into the .NET framework)&lt;/p&gt;

&lt;p&gt;Here is some code that uses the new IteratePeople method.&lt;/p&gt;

&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;// Called when a checkbox is checked.
protected void cbPerson_CheckedChanged(object sender, EventArgs e)
{
    int maleCount = 0;
    int femaleCount = 0;

    IteratePeople((person, family, item) =&amp;gt;
    {
        CheckBox cb = (CheckBox)item.FindControl(&amp;quot;cbPerson&amp;quot;);
        if (cb.Checked)
        {
            if (person.Gender == Gender.Male)
                maleCount++;
            else
                femaleCount++;
        }
    });

    btnGetPeople.Enabled = 
        maleCount == REQUIRED_MALE_COUNT &amp;amp;&amp;amp;
        femaleCount == REQUIRED_FEMALE_COUNT;

    lblState.Text = string.Format(&amp;quot;{0} male(s) selected and {1} females selected&amp;quot;,
        maleCount,
        femaleCount);
}

// Caled when the submit button is pressed
protected void btnGetPeople_Click(object sender, EventArgs e)
{
    lblSelectedPeople.Text = string.Empty;

    IteratePeople((person, family, item) =&amp;gt;
    {
        CheckBox cb = (CheckBox)item.FindControl(&amp;quot;cbPerson&amp;quot;);
        if (cb.Checked)
            lblSelectedPeople.Text += person.ToString() + &amp;quot;&amp;lt;br /&amp;gt;&amp;quot;;
    });
}&lt;/pre&gt;

&lt;p&gt;As you can see, you still have full access to the Person, Family, and DataList item, but you don’t have to duplicate the code to iterate the list. &lt;/p&gt;

&lt;p&gt;I’ve created a full sample available for &lt;a href=&quot;http://drop.io/iteratedatalist/asset/datalistiteratortest-zip&quot;&gt;download&lt;/a&gt;.&amp;#160; This sample requires .NET 3.5.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/1622299094870429155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1622299094870429155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1622299094870429155'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/07/iterating-complex-datalist-hierarchy.html' title='Iterating a Complex DataList Hierarchy With Lambda Expressions'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXu9e4R7eJ1uT8PmfKG3ymUWPCWhotbKllw2HhKJ9Z5Odlvza2YFQGgMlzBOyXl7BCPiJadW6Bq0Jc2PCrveSBJAalGv4Im4TrJx5Y8wVi_fmQUnookQvzsyNGDNaU1BcrYagUbMQrn7iX/s72-c?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-2753344534786168126</id><published>2009-06-23T07:52:00.001-05:00</published><updated>2009-06-23T07:57:45.920-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iPhone"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><title type='text'>Switching ViewControllers on Orientation Change</title><content type='html'>&lt;p&gt;Have you ever wondered how Apple achieves the smooth transition to Coverflow from the iPod app on the iPhone?&amp;#160; Today I&#39;ll go over how you can accomplish the same feature with very little code.&lt;/p&gt;  &lt;p&gt;First, there needs to be two view controllers with corresponding views.&amp;#160; One for your portrait view and one for your coverflow view.&lt;/p&gt;  &lt;p&gt;Then, you need to define which view supports which orientation&lt;/p&gt;  &lt;pre class=&quot;cpp&quot; name=&quot;code&quot;&gt;// coverflow view controller&lt;br /&gt;-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation&lt;br /&gt;{&lt;br /&gt;    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIDeviceOrientationLandscapeLeft);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// portrait view controller&lt;br /&gt;-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation&lt;br /&gt;{&lt;br /&gt;    return (interfaceOrientation == UIInterfaceOrientationPortrait);&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;Pretty standard stuff here.&amp;#160; Second, in your portrait view, you need to become a listener for the orientation change.&amp;#160; The orientation events are published to the &lt;a href=&quot;http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/index.html&quot;&gt;NSNotificationCenter&lt;/a&gt;.&amp;#160; Here I am observing any &lt;a href=&quot;http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/c/data/UIDeviceOrientationDidChangeNotification&quot;&gt;UIDeviceOrientationDidChangeNotification&lt;/a&gt; events using the constant provided by Apple.&amp;#160; &lt;/p&gt;

&lt;pre class=&quot;cpp&quot; name=&quot;code&quot;&gt;-(void)viewDidLoad&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// here we are subscribing to the device rotation notification&lt;br /&gt;[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];    &lt;br /&gt;[[NSNotificationCenter defaultCenter] addObserver:self&lt;br /&gt;                            selector:@selector(didRotate:)&lt;br /&gt;                            name:UIDeviceOrientationDidChangeNotification &lt;br /&gt;                            object:nil];&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;When the device is rotated enough to trigger an orientation change our selector, didRotate:, will be fired. In this method we are&lt;br /&gt;simply checking the current orientation and presenting the new coverflow view controller when it&#39;s in landscape.  One thing to note&lt;br /&gt;here is the &lt;a href=&quot;http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle&quot;&gt;modalTransitionStyle&lt;/a&gt;.  This is new in 3.0 and made just for this purpose.  It will fade in and out the views during &lt;br /&gt;view and dismissal.  Speaking of dismissing, it&#39;s done in the same method.  Since we are already subscribed to orientation changes,&lt;br /&gt;we are aware of when they rotate back to portrait.&lt;/p&gt;

&lt;p&gt;Here is the implementation.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot; name=&quot;code&quot;&gt;- (void)didRotate:(NSNotification *)notification&lt;br /&gt;{        &lt;br /&gt;    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];&lt;br /&gt;    &lt;br /&gt;    if ((orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight)) {&lt;br /&gt;          // present the other viewController, it&#39;s only viewable in landscape&lt;br /&gt;          CoverFlowViewController *coverFlowViewController = [[CoverFlowViewController alloc]init];&lt;br /&gt;          coverFlowViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;&lt;br /&gt;          [self presentModalViewController:coverFlowViewController Animated:YES];&lt;br /&gt;          [coverFlowViewController release];&lt;br /&gt;    }&lt;br /&gt;    else{&lt;br /&gt;          // get rid of the landscape controller&lt;br /&gt;          [self dismissModalViewControllerAnimated:YES];&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;That&#39;s it!  Now you&#39;ve got a rotating, view switching machine.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/2753344534786168126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/06/switching-viewcontrollers-on.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/2753344534786168126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/2753344534786168126'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/06/switching-viewcontrollers-on.html' title='Switching ViewControllers on Orientation Change'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-5555567495016097133</id><published>2009-06-05T08:36:00.006-05:00</published><updated>2009-06-05T08:46:30.936-05:00</updated><title type='text'>WWDC 2009</title><content type='html'>&lt;p&gt;Though things have been pretty slow here on the blog,  you can expect more frequent posts after next week.&lt;/p&gt;

&lt;p&gt;We will be at Apple&#39;s WWDC, learning new and exciting ways to develop apps on the iPhone and Mac OS X.  We will hopefully be putting up some iPhone specific posts when we get back.&lt;/p&gt;

&lt;p&gt;Are you going to WWDC?  Follow us on twitter &lt;a href=&quot;http://twitter.com/calebt&quot;&gt;@calebt&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/jabrown85&quot;&gt;@jabrown85&lt;/a&gt;!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/5555567495016097133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/06/wwdc-2009.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5555567495016097133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5555567495016097133'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/06/wwdc-2009.html' title='WWDC 2009'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-4733958827077739336</id><published>2009-05-29T09:30:00.002-05:00</published><updated>2009-05-29T09:32:49.906-05:00</updated><title type='text'>Using NHibernate MultiCriteria and LINQ</title><content type='html'>&lt;p&gt;I’m really impressed with the NHibernate.Linq add-on that’s part of the &lt;a href=&quot;http://sourceforge.net/projects/nhcontrib/&quot;&gt;NHContrib&lt;/a&gt; project.&amp;#160; It’s considered alpha software and most likely will be replaced with the work &lt;a href=&quot;http://blogs.imeta.co.uk/sstrong/archive/2009/04/16/680.aspx&quot;&gt;Steve is doing&lt;/a&gt; on NHibernate to create a more fully featured LINQ provider.&amp;#160; Knowing that, I still much prefer the strongly typed syntax of a LINQ query vs. a loosely typed ICriteria or HQL query.&lt;/p&gt;  &lt;p&gt;One problem I ran into was wanting to use the &lt;a href=&quot;http://ayende.com/Blog/archive/2007/05/20/NHibernate-Multi-Criteria.aspx&quot;&gt;MultiCriteria&lt;/a&gt; feature to batch two LINQ queries together.&amp;#160; A common example where this is useful is paging where you want the database to only return the rows to display on the current page but you also need to know the total number of rows returned by the query.&amp;#160; MultiCriteria allows you to do this in one round-trip to the database by batching the SQL together.&lt;/p&gt;  &lt;p&gt;I needed a way to grab the ICriteria constructed by the LINQ query.&amp;#160; Here’s what I came up with by looking at the source for the NHibernate.Linq project.&amp;#160; I’d recommend wrapping this in some helper function, but I have it all inline for demonstration purposes.&lt;/p&gt;  &lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;var query = from q in session.Linq&amp;lt;Person&amp;gt;()
            where q.FirstName.StartsWith(firstName)
            &amp;amp;&amp;amp; q.LastName.StartsWith(lastName)
            &amp;amp;&amp;amp; q.Phones.Any(p =&amp;gt; p.Number.Contains(phone))
            select q;

// This block of code was found in the NHibernate.Linq source
// using NHibernate.Linq.Visitors;
// using NHibernate.Engine;
System.Linq.Expressions.Expression expression = query.Expression;
expression = Evaluator.PartialEval(expression);
expression = new BinaryBooleanReducer().Visit(expression);
expression = new AssociationVisitor((ISessionFactoryImplementor)session.SessionFactory).Visit(expression);
expression = new InheritanceVisitor().Visit(expression);
expression = CollectionAliasVisitor.AssignCollectionAccessAliases(expression);
expression = new PropertyToMethodVisitor().Visit(expression);
expression = new BinaryExpressionOrderer().Visit(expression);
NHibernateQueryTranslator translator = new NHibernateQueryTranslator(session);
object results = translator.Translate(expression, ((INHibernateQueryable)query).QueryOptions);

// My LINQ query converted to ICriteria
ICriteria resultsCriteria = results as ICriteria;
// Convert to criteria that returns the row count
ICriteria rowCountCriteria = CriteriaTransformer.TransformToRowCount(resultsCriteria);

IList multiResults = session.CreateMultiCriteria()
    .Add(resultsCriteria.SetMaxResults(20))
    .Add(rowCountCriteria)
    .List();

IList people = (IList)multiResults[0];
int resultsCount = (int)((IList)multiResults[1])[0];&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/4733958827077739336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/05/using-nhibernate-multicriteria-and-linq.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/4733958827077739336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/4733958827077739336'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/05/using-nhibernate-multicriteria-and-linq.html' title='Using NHibernate MultiCriteria and LINQ'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-944887755641365491</id><published>2009-02-25T08:36:00.002-06:00</published><updated>2009-02-27T11:30:27.169-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="plugin"/><title type='text'>Creating a badge icon plugin with jQuery</title><content type='html'>&lt;p&gt;&lt;strong&gt;updated - I fixed a bug in the plugin when using it with no options&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;If you are familiar with Apple products, you&#39;ve probably seen what are known as badges. These small icons usually represent a change in the application, sometimes with details on what has changed.&lt;/p&gt;  &lt;p&gt;Today I&#39;m going to go over how to create a jQuery plugin to provide a simple, static badge.&lt;/p&gt;  &lt;p&gt;Here is our goal.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDLVDk3tQ4wE9A04hsfh90ixKqQFfCNEh1g81jv_k_1C97vMF_UgtVEw4RwfV8m28SIyHPdvmgJP2_Uf5ykETVf_MHXigx1YLglvUcG2Nwu_QuHszSkG7g_rLR9a4S2ss5j0sAaZJdZRLX/s1600-h/image2%5B3%5D.png&quot;&gt;&lt;img style=&quot;border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;139&quot; alt=&quot;image2&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz6NFAMn-RnvJVeDKNZzGILZjwc4lgEVf-g__KM-SQ9_lOtcRELSAkCmVTEdr-mNBa2azKhGRgcjM1OEaTuTietCivc5y4AnvEIGOruci1OQI0jaA3iUBtkfnLcWPkcLdHgBiP951gCJ3k/?imgmax=800&quot; width=&quot;167&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;First I&#39;ll show the HTML I&#39;m using.&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;div id=&amp;quot;firstBadge&amp;quot; class=&amp;quot;badges&amp;quot;&amp;gt;
   &amp;lt;img src=&amp;quot;images/mail.png&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt; &lt;/pre&gt;

&lt;p&gt;Pretty simple. Now I want to show the user that they have new mail without having to create another image. I also want to be able to define the notification image in CSS. Here is the CSS class I want to use.&lt;/p&gt;

&lt;pre class=&quot;css&quot; name=&quot;code&quot;&gt;    .badge
   {{
       background-image: url(images/badge.png);
       width: 45px;
       height: 45px;
   }}&lt;/pre&gt;

&lt;p&gt;Now, here&#39;s the jQuery plugin I created.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;(function($) {&lt;br /&gt;    $.fn.badge = function(action, options) {&lt;br /&gt;        // these are the default options&lt;br /&gt;        var defaults = {&lt;br /&gt;            top: 0,&lt;br /&gt;            left: 0,&lt;br /&gt;            cssClass: &#39;badge&#39;&lt;br /&gt;        };&lt;br /&gt;        return this.each(function() {&lt;br /&gt;            var obj = $(this);&lt;br /&gt;            var eleId = this.id + &amp;quot;-badge&amp;quot;;&lt;br /&gt;            // these are the 2 additional options&lt;br /&gt;            switch (action) {&lt;br /&gt;                case &#39;toggle&#39;:&lt;br /&gt;                    $(&#39;#&#39; + eleId).toggle();&lt;br /&gt;                    return;&lt;br /&gt;                case &#39;hide&#39;:&lt;br /&gt;                    $(&#39;#&#39; + eleId).hide();&lt;br /&gt;                    return;&lt;br /&gt;            }&lt;br /&gt;            // this merges the passed in settings with the default settings&lt;br /&gt;            var opts = $.extend({}, defaults, options);&lt;br /&gt;            if (!$(&amp;quot;#&amp;quot; + eleId).length) {&lt;br /&gt;                var badge_html = &amp;quot;&amp;lt;div style=&#39;position:relative;float:left;&#39;&amp;gt;&amp;lt;div id=&#39;&amp;quot; + eleId + &amp;quot;&#39; /&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;                obj.prepend(badge_html);&lt;br /&gt;            }&lt;br /&gt;            var badgeEle = $(&#39;#&#39; + eleId);&lt;br /&gt;            badgeEle.addClass(opts.cssClass);&lt;br /&gt;            badgeEle.show().css({&lt;br /&gt;                position: &#39;absolute&#39;,&lt;br /&gt;                left: opts.left,&lt;br /&gt;                top: opts.top&lt;br /&gt;            });&lt;br /&gt;            return;&lt;br /&gt;        });&lt;br /&gt;    };&lt;br /&gt;})(jQuery);&lt;/pre&gt;

&lt;p&gt;There are plenty of first jQuery plugin tutorials out on the net so I won&#39;t go over every line of this plugin. The method name is &lt;em&gt;badge&lt;/em&gt; and it has 2(optional) parameters: &lt;em&gt;action &lt;/em&gt;and &lt;em&gt;options&lt;/em&gt;. The first parameter is used to alter the behavior of the plugin. This plugin will allow you not only to apply the badge, but also &lt;em&gt;toggle &lt;/em&gt;and &lt;em&gt;hide&lt;/em&gt; it. I didn&#39;t want the end user having to set some obscure property to hide and toggle the badge, that&#39;s the reason it&#39;s not just another option. The calling code for that call will look like this.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.badges&#39;).badge(&#39;toggle&#39;);&lt;/pre&gt;

&lt;p&gt;The default options for the plugin are listed above. The offset for each axis is 0 and the CSS class to apply is going to be &#39;badge&#39;. This is just for ease-of-use, you can supply your own options as normal. Passing the options in as the second parameter.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.badges&#39;).badge(&#39;show&#39;,{
   cssClass: &#39;badge&#39;,
   left: &#39;-5px&#39;
});  &lt;/pre&gt;

&lt;p&gt;If you don&#39;t need any specific options or action you can just call this, which will use the default settings.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.badges&#39;).badge();&lt;/pre&gt;

&lt;p&gt;The plugin returns the jQuery object, so you can chain method calls.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.badges&#39;).badge().click(function(){  });&lt;/pre&gt;

&lt;p&gt;That&#39;s it! This was a short exercise for me, being my first jQuery plugin and I hope it&#39;s of some use to someone else out there. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;The Plugin&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://drop.io/jquery_badge&quot;&gt;Download&lt;/a&gt; - I developed and tested this against jQuery 1.3.2.&lt;/p&gt;

&lt;p&gt;I also added a zip file containing a demo of it.&amp;#160; We will work on getting live demos up in the future!&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;*Note that I did see someone has a badge icon for an older version of jQuery, but it requires a dependency on jQuery UI. That is something I did not want.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/944887755641365491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/02/creating-badge-icon-plugin-with-jquery.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/944887755641365491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/944887755641365491'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/02/creating-badge-icon-plugin-with-jquery.html' title='Creating a badge icon plugin with jQuery'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz6NFAMn-RnvJVeDKNZzGILZjwc4lgEVf-g__KM-SQ9_lOtcRELSAkCmVTEdr-mNBa2azKhGRgcjM1OEaTuTietCivc5y4AnvEIGOruci1OQI0jaA3iUBtkfnLcWPkcLdHgBiP951gCJ3k/s72-c?imgmax=800" height="72" width="72"/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-3621991654470266130</id><published>2009-02-19T08:43:00.001-06:00</published><updated>2009-02-21T23:35:50.266-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type='text'>jQuery live() and plugins</title><content type='html'>&lt;p&gt;&lt;u&gt;&lt;strong&gt;Problem&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;jQuery &lt;a href=&quot;http://docs.jquery.com/Events/live#typefn&quot;&gt;.live()&lt;/a&gt; is a great solution to keep your jQuery code working in heavy ajax situations where you might be adding/recreating content that needs to have jQuery applied to it (as I mentioned in my &lt;a href=&quot;http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html&quot;&gt;previous post&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;The problem is that &lt;a href=&quot;http://docs.jquery.com/Events/live#typefn&quot;&gt;.live()&lt;/a&gt; doesn&#39;t work very easily with certain plugins.&amp;#160; I really wanted a way to use &lt;a href=&quot;http://docs.jquery.com/Events/live#typefn&quot;&gt;.live()&lt;/a&gt; and the &lt;a href=&quot;http://cherne.net/brian/resources/jquery.hoverIntent.html&quot;&gt;hoverIntent plugin&lt;/a&gt; (hoverIntent basically waits to fire mouseover events until your mouse has slowed down over an element so you don&#39;t accidentally fire too many ajax requests).&amp;#160; We found this to be necessary for our &lt;a href=&quot;http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html&quot;&gt;Ajax Tooltip&lt;/a&gt; to avoid unnecessary strain on the server if the user swipes the mouse over a list of links with the tooltip applied. &lt;/p&gt;  &lt;p&gt;For example, here&#39;s the basic syntax for &lt;a href=&quot;http://docs.jquery.com/Events/live#typefn&quot;&gt;.live()&lt;/a&gt;&lt;/p&gt;  &lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.personPopupTrigger&#39;).live(&#39;mouseover&#39;, function() { /* do something */ });&lt;/pre&gt;

&lt;p&gt;And here&#39;s the syntax for hoverIntent&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(&#39;.personPopupTrigger&#39;).hoverIntent(mouseOverFunction, mouseOutFunction);&lt;/pre&gt;

&lt;p&gt;Do you see the problem?&amp;#160; The hoverIntent plugin replaces the mouseover and mouseout events with it&#39;s own.&amp;#160; There&#39;s no obvious way to attach hoverIntent to a selector while using live().&amp;#160; &lt;/p&gt;

&lt;p&gt;Fortunately, we can do some jQuery magic to make it work.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;We&#39;ll attach hoverIntent to the element the first time the user hovers the mouse over the link.&amp;#160; The trick is to use .data() to store on an element whether hoverIntent has been attached yet.&amp;#160; Then you have to manually fire the mouseover event on the element so hoverIntent can do its magic.&amp;#160; The downside is that jQuery will check to see if hoverIntent is attached every time you mouseover, but I think this is a fair tradeoff for the functionality hoverIntent provides in return.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;jQuery(function()&lt;br /&gt;{&lt;br /&gt;    $(&#39;.personPopupTrigger&#39;).live(&#39;mouseover&#39;, function()&lt;br /&gt;    {&lt;br /&gt;        if (!$(this).data(&#39;init&#39;))&lt;br /&gt;        {&lt;br /&gt;            $(this).data(&#39;init&#39;, true);&lt;br /&gt;            $(this).hoverIntent&lt;br /&gt;            (&lt;br /&gt;                function()&lt;br /&gt;                {&lt;br /&gt;                    /* mouseover logic */&lt;br /&gt;                },&lt;br /&gt;&lt;br /&gt;                function()&lt;br /&gt;                {&lt;br /&gt;                    /* mouseout logic */&lt;br /&gt;                }&lt;br /&gt;            );&lt;br /&gt;            $(this).trigger(&#39;mouseover&#39;);&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;http://www.nabble.com/Re%3A-jQuery-1.3-%2B-live-livequery-%2B-draggable-problem-p21345570s27240.html&quot;&gt;This post&lt;/a&gt; was the inspiration, but I had to add firing the mouseover event.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Updated Ajax Tooltip JavaScript&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Here&#39;s the updated version of the javascript for the &lt;a href=&quot;http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html&quot;&gt;Ajax Tooltip&lt;/a&gt;.&amp;#160; This requires jQuery 1.3.1 and the &lt;a href=&quot;http://cherne.net/brian/resources/jquery.hoverIntent.html&quot;&gt;hoverIntent plugin&lt;/a&gt;.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(function()&lt;br /&gt;{&lt;br /&gt;    var hideDelay = 500;&lt;br /&gt;    var currentID;&lt;br /&gt;    var hideTimer = null;&lt;br /&gt;    var ajax = null;&lt;br /&gt;    var hideFunction = function()&lt;br /&gt;    {&lt;br /&gt;        if (hideTimer)&lt;br /&gt;            clearTimeout(hideTimer);&lt;br /&gt;        hideTimer = setTimeout(function()&lt;br /&gt;        {&lt;br /&gt;            currentPosition = { left: &#39;0px&#39;, top: &#39;0px&#39; };&lt;br /&gt;            container.css(&#39;display&#39;, &#39;none&#39;);&lt;br /&gt;        }, hideDelay);&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    var currentPosition = { left: &#39;0px&#39;, top: &#39;0px&#39; };&lt;br /&gt;&lt;br /&gt;    // One instance that&#39;s reused to show info for the current person&lt;br /&gt;    var container = $(&#39;&amp;lt;div id=&amp;quot;personPopupContainer&amp;quot;&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;table width=&amp;quot;&amp;quot; border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot; class=&amp;quot;personPopupPopup&amp;quot;&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;tr&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;corner topLeft&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;corner topRight&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;/tr&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;tr&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;left&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td&amp;gt;&amp;lt;div id=&amp;quot;personPopupContent&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;right&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;/tr&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;tr&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;corner bottomLeft&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;bottom&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;   &amp;lt;td class=&amp;quot;corner bottomRight&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;/tr&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;/table&amp;gt;&#39;&lt;br /&gt;        + &#39;&amp;lt;/div&amp;gt;&#39;);&lt;br /&gt;&lt;br /&gt;    $(&#39;body&#39;).append(container);&lt;br /&gt;&lt;br /&gt;    $(&#39;.personPopupTrigger&#39;).live(&#39;mouseover&#39;, function()&lt;br /&gt;    {&lt;br /&gt;        if (!$(this).data(&#39;hoverIntentAttached&#39;))&lt;br /&gt;        {&lt;br /&gt;            $(this).data(&#39;hoverIntentAttached&#39;, true);&lt;br /&gt;            $(this).hoverIntent&lt;br /&gt;            (&lt;br /&gt;                // hoverIntent mouseOver&lt;br /&gt;                function()&lt;br /&gt;                {&lt;br /&gt;                    if (hideTimer)&lt;br /&gt;                        clearTimeout(hideTimer);&lt;br /&gt;&lt;br /&gt;                    // format of &#39;rel&#39; tag: pageid,personguid&lt;br /&gt;                    var settings = $(this).attr(&#39;rel&#39;).split(&#39;,&#39;);&lt;br /&gt;                    var pageID = settings[0];&lt;br /&gt;                    currentID = settings[1];&lt;br /&gt;&lt;br /&gt;                    // If no guid in url rel tag, don&#39;t popup blank&lt;br /&gt;                    if (currentID == &#39;&#39;)&lt;br /&gt;                        return;&lt;br /&gt;&lt;br /&gt;                    var pos = $(this).offset();&lt;br /&gt;                    var width = $(this).width();&lt;br /&gt;                    var reposition = { left: (pos.left + width) + &#39;px&#39;, top: pos.top - 5 + &#39;px&#39; };&lt;br /&gt;&lt;br /&gt;                    // If the same popup is already shown, then don&#39;t requery&lt;br /&gt;                    if (currentPosition.left == reposition.left &amp;amp;&amp;amp;&lt;br /&gt;                        currentPosition.top == reposition.top)&lt;br /&gt;                        return;&lt;br /&gt;&lt;br /&gt;                    container.css({&lt;br /&gt;                        left: reposition.left,&lt;br /&gt;                        top: reposition.top&lt;br /&gt;                    });&lt;br /&gt;&lt;br /&gt;                    currentPosition = reposition;&lt;br /&gt;&lt;br /&gt;                    $(&#39;#personPopupContent&#39;).html(&#39;&amp;amp;nbsp;&#39;);&lt;br /&gt;&lt;br /&gt;                    if (ajax)&lt;br /&gt;                    {&lt;br /&gt;                        ajax.abort();&lt;br /&gt;                        ajax = null;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    ajax = $.ajax({&lt;br /&gt;                        type: &#39;GET&#39;,&lt;br /&gt;                        url: &#39;ajaxhelper.aspx&#39;,&lt;br /&gt;                        data: &#39;page=&#39; + pageID + &#39;&amp;amp;guid=&#39; + currentID,&lt;br /&gt;                        success: function(data)&lt;br /&gt;                        {&lt;br /&gt;                            // Verify that we&#39;re pointed to a page that returned the expected results.&lt;br /&gt;                            if (data.indexOf(&#39;personPopupResult&#39;) &amp;lt; 0)&lt;br /&gt;                            {&lt;br /&gt;                                $(&#39;#personPopupContent&#39;).html(&#39;&amp;lt;span style=&amp;quot;color:red&amp;quot; class=&amp;quot;smallText&amp;quot;&amp;gt;Page &#39; + pageID + &#39; did not return a valid result for person &#39; + currentID + &#39;.&amp;lt;br /&amp;gt;Please have your administrator check the error log.&amp;lt;/span&amp;gt;&#39;);&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                            // Verify requested person is this person since we could have multiple ajax&lt;br /&gt;                            // requests out if the server is taking a while.&lt;br /&gt;                            if (data.indexOf(currentID) &amp;gt; 0)&lt;br /&gt;                            {&lt;br /&gt;                                var text = $(data).find(&#39;.personPopupResult&#39;).html();&lt;br /&gt;                                $(&#39;#personPopupContent&#39;).html(text);&lt;br /&gt;                            }&lt;br /&gt;                        }&lt;br /&gt;                    });&lt;br /&gt;&lt;br /&gt;                    container.css(&#39;display&#39;, &#39;block&#39;);&lt;br /&gt;                },&lt;br /&gt;                // hoverIntent mouseOut&lt;br /&gt;                hideFunction&lt;br /&gt;            );&lt;br /&gt;            // Fire mouseover so hoverIntent can start doing its magic&lt;br /&gt;            $(this).trigger(&#39;mouseover&#39;);&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    // Allow mouse over of details without hiding details&lt;br /&gt;    $(&#39;#personPopupContainer&#39;).mouseover(function()&lt;br /&gt;    {&lt;br /&gt;        if (hideTimer)&lt;br /&gt;            clearTimeout(hideTimer);&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    // Hide after mouseout&lt;br /&gt;    $(&#39;#personPopupContainer&#39;).mouseout(hideFunction);&lt;br /&gt;});&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/3621991654470266130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/02/jquery-live-and-plugins.html#comment-form' title='37 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3621991654470266130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/3621991654470266130'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/02/jquery-live-and-plugins.html' title='jQuery live() and plugins'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-738661170315668243</id><published>2009-02-12T08:48:00.003-06:00</published><updated>2009-11-04T15:52:22.125-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type='text'>jQuery Ajax Tooltip</title><content type='html'>&lt;p style=&quot;background-color: rgb(227, 227, 227);&quot;&gt;&lt;b&gt;Update:&lt;/b&gt; I&#39;ve &lt;a href=&quot;http://rndnext.blogspot.com/2009/02/jquery-live-and-plugins.html&quot;&gt;updated&lt;/a&gt; the JavaScript to use the hoverIntent plugin to avoid unnecessary ajax calls when moving the mouse quickly over a list of items.&lt;/p&gt;
&lt;p&gt;We&#39;re taking a bit of a break from WPF right now, so I&#39;m back working on our ASP.NET project.&lt;/p&gt;  &lt;p&gt;Our application is very person centric, so we wanted an easy way to pop up a &quot;tooltip&quot; with more information about a person whenever you see a person&#39;s name.  For example, here are some search results.  When you hover over a name, more information appears.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiINPlO-Gs4zYW9WfB34XH4eVC4I3Y1Q0vfbRigzBk-Hb87ouWv1PbV9MxQNUY7I9bc3Wnfknq8gvU1Ehfg0mDD6gp61Ad73HH5xTX6Tn5cngESQz5MOIGnCz_PMHzpRUxlwwdDXiz2b0hk/s1600-h/image9.png&quot;&gt;&lt;img style=&quot;border-width: 0px;&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWUOsHD6B3JFhq74GO4HWQbo0pqBMG8qoR_p27aBztnd6mCYMFN1boDA4JIAbBuLlceW2HsfHhgrQ0Qcs-FCZEUyel7sYJC2YQQQ7FboDeBdZgH4_TojY4ryOsUFCxbszGgjmsaXpd1QAj/?imgmax=800&quot; width=&quot;598&quot; border=&quot;0&quot; height=&quot;382&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This is very much based on the &lt;a href=&quot;http://jqueryfordesigners.com/coda-popup-bubbles/&quot;&gt;Coda Popup Bubble&lt;/a&gt; example for jQuery that&#39;s been going around with a few important differences:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The information is requested via AJAX, so you don&#39;t have to include all of this extra information in a hidden div.  This keeps your markup smaller for grids with tons of names in it. &lt;/li&gt;    &lt;li&gt;When you mouse over another name, the previous one will disappear.  If you tried this with the original Coda example, you&#39;d end up with a weird streaking animation since there&#39;s a delay before the div is hidden. &lt;/li&gt;    &lt;li&gt;Works in IE (just turned off the fade animation) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;Note that this requires jQuery 1.3.1.  I found out that the new &lt;a href=&quot;http://docs.jquery.com/Events/live#typefn&quot;&gt;.live()&lt;/a&gt; functionality is very useful for ajax applications.  Previously, if you bind a handler at startup, it will apply to elements that currently exist.  The new live() functionality makes it to where you can apply events to elements that are created in the future.  This means I can create a new link via ajax and it will still work with the hover tooltip.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;Markup&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;All you need to do is specify a certain css class that jquery expects, and we&#39;re using the &quot;rel&quot; tag to contain data to pass to our ajax helper page.&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;a class=&quot;personPopupTrigger&quot; href=&quot;&amp;lt;link to person&amp;gt;&quot; rel=&quot;4218,a17bee64-8593-436e-a2f8-599a626370df&quot;&amp;gt;House, Devon&amp;lt;/a&amp;gt;
&amp;lt;a class=&quot;personPopupTrigger&quot; href=&quot;&amp;lt;link to person&amp;gt;&quot; rel=&quot;4218,f6434101-15bf-4c06-bbb2-fbe8c111b948&quot;&amp;gt;House, Gregory&amp;lt;/a&amp;gt;
&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;JavaScript&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run this on startup, and it will convert all of your links with the &quot;personPopupTrigger&quot; class to have the tooltip.&lt;/p&gt;

&lt;p&gt;The container is the global container for the content.  It&#39;s repositioned whenever a new link is hovered over.&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;$(function()
{
  var hideDelay = 500;  
  var currentID;
  var hideTimer = null;

  // One instance that&#39;s reused to show info for the current person
  var container = $(&#39;&amp;lt;div id=&quot;personPopupContainer&quot;&amp;gt;&#39;
      + &#39;&amp;lt;table width=&quot;&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; align=&quot;center&quot; class=&quot;personPopupPopup&quot;&amp;gt;&#39;
      + &#39;&amp;lt;tr&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;corner topLeft&quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;top&quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;corner topRight&quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;
      + &#39;&amp;lt;/tr&amp;gt;&#39;
      + &#39;&amp;lt;tr&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;left&quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td&amp;gt;&amp;lt;div id=&quot;personPopupContent&quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;right&quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;
      + &#39;&amp;lt;/tr&amp;gt;&#39;
      + &#39;&amp;lt;tr&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;corner bottomLeft&quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;bottom&quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&#39;
      + &#39;   &amp;lt;td class=&quot;corner bottomRight&quot;&amp;gt;&amp;lt;/td&amp;gt;&#39;
      + &#39;&amp;lt;/tr&amp;gt;&#39;
      + &#39;&amp;lt;/table&amp;gt;&#39;
      + &#39;&amp;lt;/div&amp;gt;&#39;);

  $(&#39;body&#39;).append(container);

  $(&#39;.personPopupTrigger&#39;).live(&#39;mouseover&#39;, function()
  {
      // format of &#39;rel&#39; tag: pageid,personguid
      var settings = $(this).attr(&#39;rel&#39;).split(&#39;,&#39;);
      var pageID = settings[0];
      currentID = settings[1];

      // If no guid in url rel tag, don&#39;t popup blank
      if (currentID == &#39;&#39;)
          return;

      if (hideTimer)
          clearTimeout(hideTimer);

      var pos = $(this).offset();
      var width = $(this).width();
      container.css({
          left: (pos.left + width) + &#39;px&#39;,
          top: pos.top - 5 + &#39;px&#39;
      });

      $(&#39;#personPopupContent&#39;).html(&#39;&amp;amp;nbsp;&#39;);

      $.ajax({
          type: &#39;GET&#39;,
          url: &#39;personajax.aspx&#39;,
          data: &#39;page=&#39; + pageID + &#39;&amp;amp;guid=&#39; + currentID,
          success: function(data)
          {
              // Verify that we&#39;re pointed to a page that returned the expected results.
              if (data.indexOf(&#39;personPopupResult&#39;) &amp;lt; 0)
              {
                  $(&#39;#personPopupContent&#39;).html(&#39;&amp;lt;span &amp;gt;Page &#39; + pageID + &#39; did not return a valid result for person &#39; + currentID + &#39;.&amp;lt;br /&amp;gt;Please have your administrator check the error log.&amp;lt;/span&amp;gt;&#39;);
              }

              // Verify requested person is this person since we could have multiple ajax
              // requests out if the server is taking a while.
              if (data.indexOf(currentID) &amp;gt; 0)
              {                  
                  var text = $(data).find(&#39;.personPopupResult&#39;).html();
                  $(&#39;#personPopupContent&#39;).html(text);
              }
          }
      });

      container.css(&#39;display&#39;, &#39;block&#39;);
  });

  $(&#39;.personPopupTrigger&#39;).live(&#39;mouseout&#39;, function()
  {
      if (hideTimer)
          clearTimeout(hideTimer);
      hideTimer = setTimeout(function()
      {
          container.css(&#39;display&#39;, &#39;none&#39;);
      }, hideDelay);
  });

  // Allow mouse over of details without hiding details
  $(&#39;#personPopupContainer&#39;).mouseover(function()
  {
      if (hideTimer)
          clearTimeout(hideTimer);
  });

  // Hide after mouseout
  $(&#39;#personPopupContainer&#39;).mouseout(function()
  {
      if (hideTimer)
          clearTimeout(hideTimer);
      hideTimer = setTimeout(function()
      {
          container.css(&#39;display&#39;, &#39;none&#39;);
      }, hideDelay);
  });
});&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;pre class=&quot;js&quot; name=&quot;code&quot;&gt;#personPopupContainer
{
    position:absolute;
    left:0;
    top:0;
    display:none;
    z-index: 20000;
}

.personPopupPopup
{
}

#personPopupContent
{
    background-color: #FFF;
    min-width: 175px;
    min-height: 50px;
}

.personPopupPopup .personPopupImage
{
    margin: 5px;
    margin-right: 15px;
}

.personPopupPopup .corner 
{
    width: 19px;
    height: 15px;
}
    
.personPopupPopup .topLeft 
{
    background: url(../images/personpopup/balloon_topLeft.png) no-repeat;
}
    
.personPopupPopup .bottomLeft 
{
    background: url(../images/personpopup/balloon_bottomLeft.png) no-repeat;
}
    
.personPopupPopup .left 
{
    background: url(../images/personpopup/balloon_left.png) repeat-y;
}
    
.personPopupPopup .right 
{
    background: url(../images/personpopup/balloon_right.png) repeat-y;
}
    
.personPopupPopup .topRight 
{
    background: url(../images/personpopup/balloon_topRight.png) no-repeat;
}
    
.personPopupPopup .bottomRight 
{
    background: url(../images/personpopup/balloon_bottomRight.png) no-repeat;
}
    
.personPopupPopup .top 
{
    background: url(../images/personpopup/balloon_top.png) repeat-x;
}
    
.personPopupPopup .bottom 
{
    background: url(../images/personpopup/balloon_bottom.png) repeat-x;
    text-align: center;
}&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Images&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://calebt.googlepages.com/person_tooltip_images.zip&quot;&gt;Download&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Ajax Helper Page&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;I&#39;m not going to include a code sample for this since it&#39;s very specific to our application.  It basically accepts query string parameters of &quot;page&quot; and &quot;guid&quot; and spits out details about that person.&lt;/p&gt;

&lt;p&gt;Note: my example expects the ajax helper to return the content in a div with a css class of &#39;personPopupResult&#39;.  Also, it returns the person&#39;s guid in the result to verify that the returned result is for the same person currently selected since an ajax request might take a while in some cases and return an old result.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/738661170315668243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html#comment-form' title='46 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/738661170315668243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/738661170315668243'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html' title='jQuery Ajax Tooltip'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWUOsHD6B3JFhq74GO4HWQbo0pqBMG8qoR_p27aBztnd6mCYMFN1boDA4JIAbBuLlceW2HsfHhgrQ0Qcs-FCZEUyel7sYJC2YQQQ7FboDeBdZgH4_TojY4ryOsUFCxbszGgjmsaXpd1QAj/s72-c?imgmax=800" height="72" width="72"/><thr:total>46</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-4955809923118137927</id><published>2009-01-09T10:48:00.001-06:00</published><updated>2009-01-09T15:50:35.907-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="validation"/><category scheme="http://www.blogger.com/atom/ns#" term="wpf"/><title type='text'>Validation in WPF – The Disconnect</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://karlshifflett.wordpress.com/&quot;&gt;Karl Shifflett&lt;/a&gt; is just one of the many WPF gurus we follow here at the office.&amp;#160; As we are getting started on our first LOB WPF application, their experience has been a key part of our learning process.&amp;#160; I mention Karl because he recently posted an article on &lt;a href=&quot;http://karlshifflett.wordpress.com/2008/12/29/updated-input-validation-ui-exceptions-model-validation-errors/&quot;&gt;Input Validation&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;As I glanced through the code the first time, I didn’t get it.&amp;#160; Because I hadn’t thoroughly investigated validation in WPF yet, I didn’t realize &lt;em&gt;why&lt;/em&gt; all this validation framework was needed. &lt;/p&gt;  &lt;p&gt;Karl explains it the best in his &lt;a href=&quot;http://karlshifflett.wordpress.com/mvvm/input-validation-ui-exceptions-model-validation-errors/&quot;&gt;first post&lt;/a&gt;, so I won’t reiterate all of it.&amp;#160;&amp;#160; The issue that escaped me while playing around with WPF was &lt;strong&gt;the disconnect between the UI and the ViewModel when binding&lt;/strong&gt;.&amp;#160; This statement itself seems like a major problem, and it is if you aren’t aware. Here is the problem via Karl.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;A TextBox in the View is bound to an integer property on the Model.&amp;#160; That integer property has an associated &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo.aspx&quot;&gt;IDataErrorInfo&lt;/a&gt; validation rule that requires that the property value be between 0 and 100.&lt;/p&gt;    &lt;p&gt;If the user enters a value less than 0 or greater than 100, the Model will report an error that the binding pipeline will pickup and if the TextBox has a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.windows.controls.validation.errortemplate.aspx&quot;&gt;Validation.ErrorTemplate&lt;/a&gt;, will display some error message to the user.&lt;/p&gt;    &lt;p&gt;Now the user enters 5b and tabs to the next field.&amp;#160; Since 5b is not an integer, the binding pipeline will get an exception when attempting to set the property value on the Model since there is a type mismatch.&lt;/p&gt;    &lt;p&gt;Now the TextBox.Text property on the View is 5b, the Model does not know that the View has an invalid value and if the Model’s current value is within the limits of any applied validation rules, the Model thinks it’s valid.&lt;/p&gt;    &lt;p&gt;So you can see that under these circumstances there is a disconnect between the View and Model.&amp;#160; It is this disconnect that I would like to address and provide a solution for.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The framework Karl posted solves this problem by giving you a way to check the View exceptions from your ViewModel without tightly coupling the two.&amp;#160; This way you can let the user know that the value they entered is incorrect and prevent them from trying to save incorrect values.&amp;#160; The View pushes it’s errors to the ViewModel and the ViewModel then can check against them and respond appropriately.&amp;#160; This is all done via base classes and it doesn’t violate the separation by exposing the View on the actual ViewModel.&lt;/p&gt;  &lt;p&gt;We implemented this framework did some tweaks and changes to suit our needs.&amp;#160; So now we can check for all types of errors, Model and UI,&amp;#160; from the ViewModel.&lt;/p&gt;  &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public bool IsValid &lt;br /&gt;{ &lt;br /&gt;    get &lt;br /&gt;    {&lt;br /&gt;        return string.IsNullOrEmpty(UIValidationErrorUserMessages) &amp;amp;&amp;amp; Model.IsValid; &lt;br /&gt;    } &lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;I highly recommend taking a look if you are starting a LOB application and haven’t rolled your own solution.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/4955809923118137927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2009/01/validation-in-wpf-disconnect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/4955809923118137927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/4955809923118137927'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2009/01/validation-in-wpf-disconnect.html' title='Validation in WPF – The Disconnect'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-5313680006062366276</id><published>2008-12-30T10:21:00.001-06:00</published><updated>2008-12-30T10:21:36.336-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="wpf"/><title type='text'>Set WPF ListBox SelectedItem on Hover</title><content type='html'>&lt;p&gt;So as previously &lt;a href=&quot;http://rndnext.blogspot.com/2008/12/combobox-bug.html&quot;&gt;mentioned&lt;/a&gt;, the ComboBox doesn&#39;t work as expected regarding the highlighted item vs. focused item.&amp;#160; &lt;/p&gt;  &lt;p&gt;It turns out that we can make the ListBox work like we want.&amp;#160; At first glance, it looks like the ListBox won&#39;t work because there&#39;s only a SelectedItem but not a HighlightedItem.&amp;#160; This means it works great for keyboard navigation, but the item will not be highlighted when you mouseover as it does with the ComboBox.&lt;/p&gt;  &lt;p&gt;There&#39;s a simple way to make this work:&lt;/p&gt;  &lt;p&gt;1) Add a MouseEnter event inside of your ListBox&#39;s ItemTemplate:&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;ListBox x:Name=&amp;quot;lbResults&amp;quot; ItemsSource=&amp;quot;{Binding Results}&amp;quot; MaxHeight=&amp;quot;400&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;ListBox.ItemTemplate&amp;gt;&lt;br /&gt;        &amp;lt;DataTemplate&amp;gt;&lt;br /&gt;            &amp;lt;Border BorderThickness=&amp;quot;1&amp;quot; BorderBrush=&amp;quot;Black&amp;quot; MouseEnter=&amp;quot;ListBoxItem_MouseEnter&amp;quot;&amp;gt;&lt;br /&gt;                &amp;lt;Grid&amp;gt;&lt;br /&gt;                    &amp;lt;Grid.ColumnDefinitions&amp;gt;&lt;br /&gt;                        &amp;lt;ColumnDefinition /&amp;gt;&lt;br /&gt;                        &amp;lt;ColumnDefinition /&amp;gt;&lt;br /&gt;                    &amp;lt;/Grid.ColumnDefinitions&amp;gt;&lt;br /&gt;                    &amp;lt;Grid.RowDefinitions&amp;gt;&lt;br /&gt;                        &amp;lt;RowDefinition /&amp;gt;&lt;br /&gt;                        &amp;lt;RowDefinition /&amp;gt;&lt;br /&gt;                    &amp;lt;/Grid.RowDefinitions&amp;gt;&lt;br /&gt;                    &amp;lt;TextBlock Text=&amp;quot;{Binding FullName}&amp;quot; /&amp;gt;&lt;br /&gt;                    &amp;lt;TextBlock Grid.Column=&amp;quot;1&amp;quot; Text=&amp;quot;{Binding Email}&amp;quot; /&amp;gt;&lt;br /&gt;                    &amp;lt;TextBlock Grid.Row=&amp;quot;1&amp;quot; Grid.ColumnSpan=&amp;quot;2&amp;quot; Text=&amp;quot;{Binding Address}&amp;quot; /&amp;gt;&lt;br /&gt;                &amp;lt;/Grid&amp;gt;&lt;br /&gt;            &amp;lt;/Border&amp;gt;&lt;br /&gt;        &amp;lt;/DataTemplate&amp;gt;&lt;br /&gt;    &amp;lt;/ListBox.ItemTemplate&amp;gt;&lt;br /&gt;&amp;lt;/ListBox&amp;gt;&lt;/pre&gt;

&lt;p&gt;2) In the .xaml.cs, add this:&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;// Hover effect&lt;br /&gt;private void ListBoxItem_MouseEnter(object sender, MouseEventArgs e)&lt;br /&gt;{&lt;br /&gt;    lbResults.SelectedItem = (sender as Border).DataContext;&lt;br /&gt;    if (!lbResults.IsFocused)&lt;br /&gt;        lbResults.Focus();&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;The end result is that whenever you put your mouse over an item in the ListBox, it will highlight the item and make it the SelectedItem.&lt;/p&gt;

&lt;p&gt;We tried using a &lt;a href=&quot;http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=355087&quot;&gt;Trigger&lt;/a&gt; to set IsSelected to true when IsMouseOver is true, but this does not work.&amp;#160; I&#39;m not sure if it&#39;s a bug, but it definitely results in some unexpected behavior since it appears that SelectedItem is not set on the ListBox when IsSelected is set on the ListBoxItem.&lt;/p&gt;

&lt;p&gt;The autocomplete box is coming along nicely.&amp;#160; I hope to post it sometime soon.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/5313680006062366276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2008/12/set-wpf-listbox-selecteditem-on-hover.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5313680006062366276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/5313680006062366276'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2008/12/set-wpf-listbox-selecteditem-on-hover.html' title='Set WPF ListBox SelectedItem on Hover'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-1980114796632347298</id><published>2008-12-29T13:43:00.001-06:00</published><updated>2009-01-09T15:51:21.539-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bug"/><category scheme="http://www.blogger.com/atom/ns#" term="wpf"/><title type='text'>ComboBox Bug</title><content type='html'>&lt;p&gt;Today we found a small, but annoying, bug in the WPF ComboBox.&amp;#160; As Caleb &lt;a href=&quot;http://rndnext.blogspot.com/2008/12/selecting-wpf-comboboxitem-with-tab-key.html&quot;&gt;mentioned before&lt;/a&gt;, we are implementing an autocomplete control.&amp;#160; Since our implementation is a bit different, we are programmatically opening and closing the dropdown list using &lt;em&gt;IsDropDownOpen.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;What we want to happen when we open the dropdown is to highlight(select) the first item when the user presses the &#39;Tab&#39; key.&amp;#160; So to implement this we added a &lt;em&gt;Preview_KeyDown&lt;/em&gt; event to it. &lt;/p&gt;  &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;if (e.Key == Key.Tab)&lt;br /&gt;{&lt;br /&gt;    if (cbResults.IsDropDownOpen)&lt;br /&gt;    {                    &lt;br /&gt;        ComboBoxItem item = ((ComboBoxItem)cbResults.ItemContainerGenerator.ContainerFromIndex(0));                &lt;br /&gt;        item.Focus();       &lt;br /&gt;        e.Handled = true;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;Simple enough, we are just getting the first ComboBoxItem and giving it focus. Well it works...the &lt;strong&gt;First&lt;/strong&gt; time.&amp;#160; If the ComboBox is open and the user presses &#39;Tab&#39; the first item is highlighted blue and focused.&amp;#160; However, if you tab back to the control and try again, it only &lt;em&gt;focuses&lt;/em&gt; it.&amp;#160; It does not highlight the item blue as it did before. &lt;/p&gt;

&lt;p&gt;After digging through reflector, Caleb found the reason.&amp;#160; Here is the basic code for a ComboBoxItem&#39;s &lt;em&gt;OnGotKeyboardFocus&lt;/em&gt;&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;e.Handled = true;&lt;br /&gt;ComboBox parentComboBox = this.ParentComboBox;&lt;br /&gt;if (parentComboBox != null)&lt;br /&gt;{&lt;br /&gt;    parentComboBox.NotifyComboBoxItemEnter(this);&lt;br /&gt;}&lt;br /&gt;base.OnGotKeyboardFocus(e);&lt;br /&gt;&lt;/pre&gt;

&lt;p&gt;Now, nothing looks wrong here.&amp;#160; We want to notify the item&#39;s ComboBox that we have entered.&amp;#160; Here is the problem, this is the &lt;em&gt;NotifyComboBoxItemEnter&lt;/em&gt; function.&lt;/p&gt;

&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;internal void NotifyComboBoxItemEnter(ComboBoxItem item)&lt;br /&gt;{&lt;br /&gt;    if ((this.IsDropDownOpen &amp;amp;&amp;amp; (Mouse.Captured == this)) &amp;amp;&amp;amp; base.DidMouseMove())&lt;br /&gt;    {&lt;br /&gt;        this.HighlightedElement = item;&lt;br /&gt;        if (!this.IsEditable &amp;amp;&amp;amp; !item.IsKeyboardFocusWithin)&lt;br /&gt;        {&lt;br /&gt;            item.Focus();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;See anything wrong?&amp;#160; Check that last condition.&amp;#160; It is checking to ensure the mouse has moved before it will highlight and focus the item.&amp;#160; Why on earth are they checking that in the &lt;em&gt;OnGot&lt;strong&gt;Keyboard&lt;/strong&gt;Focus&lt;/em&gt;?&amp;#160;&amp;#160; It only works the first time because the mouse position hasn&#39;t been recorded to compare against yet.&amp;#160; The ONLY way around this issue is to move the mouse programmatically.&amp;#160; Yes, you have to &lt;strong&gt;move the user&#39;s mouse&lt;/strong&gt; to make the item highlight.&lt;/p&gt;

&lt;p&gt;The mistake is clearly an oversight.&amp;#160; That method is called by all the mouse events on a ComboBoxItem as well.&amp;#160; I&#39;m going to submit a bug, but who knows how long that will take to get into the next release.&amp;#160; This is one of those times you wish the .NET framework was open source, we could fix the issue, submit a patch and move along. &lt;/p&gt;

&lt;p&gt;Also note, we aren&#39;t going to move the user&#39;s mouse ;) we are looking at creating our own selector control and avoiding the ComboBox for now.&lt;/p&gt;
Edit I submitted a &lt;a href=&quot;https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=389959&quot;&gt;bug&lt;/a&gt;  </content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/1980114796632347298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2008/12/combobox-bug.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1980114796632347298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/1980114796632347298'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2008/12/combobox-bug.html' title='ComboBox Bug'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-7536767205606818414</id><published>2008-12-26T09:39:00.000-06:00</published><updated>2008-12-26T10:09:19.331-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="blend"/><category scheme="http://www.blogger.com/atom/ns#" term="wpf"/><title type='text'>Another reason to use Expression Blend to design your WPF Applications</title><content type='html'>&lt;p&gt;As if there aren&#39;t already enough reasons, this simple one saves tons of time and frustration.&lt;/p&gt;  &lt;p&gt;Say you want to have an automatically sized window.&amp;#160; Have you ever tried to edit one of those windows in visual studio?&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_uUytolMNhGkP10Xd3qKte0oyEQEPS95-BGcovUqqNFz8xV-ZraHFyjpPqpUYDpm5Jm15v2Q-gz0kcDPO6ldItMW1rO0kCNQASKLBias5k9TGE1NualbJbCoW9T72P58lI58cpwRxFIPo/s1600-h/image%5B7%5D.png&quot;&gt;&lt;img style=&quot;border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;213&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxBVGH_3amxSTR5J3HqrWmzgv0CJhnig_YWCcwgA8Ofo1A8tjik1Bif1o6FbRNfZlTqJtXoHQ-2vThYUModNWWOl-e1FUEcKJfDI1Jdu-MlHDcHWGXYtgQbZQMf-fFBzcr261dcy7nuZnn/?imgmax=800&quot; width=&quot;284&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Not very designer friendly.&amp;#160; You can&#39;t even see what it looks like without setting the height and width.&amp;#160; Then you have to remove them before you save or your form will be that static width and height at runtime.&amp;#160; Tweaking a layout is out of the question.&lt;/p&gt;  &lt;p&gt;In for the rescue is Expression Blend.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRU6SNpQTyXHWtnvJTc140IhPfG87lTq5rDIY4cHkWnnyqA0LX7VU0vBBfiw0sIYrcgC5yZ9N2Bpr2QmM89CBQh_43heNuJjuGnJJ0GVTwGngioBfc5Te5sjkdNZjEdQMwEqLGzP78uRFT/s1600-h/image%5B6%5D.png&quot;&gt;&lt;img style=&quot;border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;159&quot; alt=&quot;image&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaL9hdP1Vvtf8enT61OJ8UHfd8HvTU_ShyQnnEG0hRfrR3KXVxNQPUIzpUlCNjwGlKxNXuFjKtHW5Pjry0VMM4cXWPEHaR_T_Xz31jHOz5VUIWprcryBV8Uqqag0Jp3SxAYPoxHzHnDxo3/?imgmax=800&quot; width=&quot;412&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;See those little blue handles?&amp;#160; Those are &lt;em&gt;&lt;strong&gt;design time&lt;/strong&gt;&lt;/em&gt; handles.&amp;#160; You can set the width and height and only Expression Blend will recognize them.&amp;#160; Now you can size your window to a normal size and see how your control layout flows.&lt;/p&gt;  &lt;p&gt;&lt;span class=&quot;kwrd&quot;&gt;This is the XAML it adds to your window.&amp;#160; Blend will do this automatically for you and it won&#39;t cause any adverse behavior.&lt;/span&gt;&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;    xmlns:d=&amp;quot;http://schemas.microsoft.com/expression/blend/2008&amp;quot; 
    xmlns:mc=&amp;quot;http://schemas.openxmlformats.org/markup-compatibility/2006&amp;quot; 
    mc:Ignorable=&amp;quot;d&amp;quot; d:DesignHeight=&amp;quot;94&amp;quot; d:DesignWidth=&amp;quot;384&amp;quot;&lt;/pre&gt;&lt;p&gt;This saves a ton of headaches and prevents extra code, like setting the width and height in the code behind for design mode.&amp;#160; The only issue with this method is the fact that it &lt;em&gt;doesn&#39;t&lt;/em&gt; work in visual studio.&amp;#160; I&#39;m hoping they will eventually add support for it in the future updates, but you should be using blend anyway.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/7536767205606818414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2008/12/another-reason-to-use-expression-blend.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7536767205606818414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7536767205606818414'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2008/12/another-reason-to-use-expression-blend.html' title='Another reason to use Expression Blend to design your WPF Applications'/><author><name>Jesse</name><uri>http://www.blogger.com/profile/10805323498631587726</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9pzsuTSt3ErpOw4GFzP1_NdanLJbqWm3tAFYmzULJfaoFaqKgk613_gQe9faSOl5lNhzqepakux5k2B5E_ZscAri6jDp6agENGfPiolkTa---f1ZmTsv28lfKZLXc1c/s220/DSCN3062.JPG'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxBVGH_3amxSTR5J3HqrWmzgv0CJhnig_YWCcwgA8Ofo1A8tjik1Bif1o6FbRNfZlTqJtXoHQ-2vThYUModNWWOl-e1FUEcKJfDI1Jdu-MlHDcHWGXYtgQbZQMf-fFBzcr261dcy7nuZnn/s72-c?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-953670387080576871.post-7976744021317294947</id><published>2008-12-23T13:20:00.001-06:00</published><updated>2009-01-09T15:51:58.165-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="wpf"/><title type='text'>Selecting a WPF ComboBoxItem with the Tab Key</title><content type='html'>&lt;p&gt;The WPF ComboBox doesn&#39;t work out of the box as I expected when IsEditable=False.&lt;/p&gt;  &lt;p&gt;This is how I expect it to work:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Expand the ComboBox &lt;/li&gt;    &lt;li&gt;Use the up/down arrow keys to find the item you want to select. &lt;/li&gt;    &lt;li&gt;Press the &amp;quot;tab&amp;quot; key on the current item to select it and then move on to the next field. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In reality, it cycles through all of the ComboBoxItems in the ComboBox when you hit the tab key.&amp;#160; You have to either hit &amp;quot;Enter&amp;quot; or click on the item with your mouse to select it!&lt;/p&gt;  &lt;p&gt;(Note that it does work as I expect when IsEditable=True for some reason)&lt;/p&gt;  &lt;p&gt;Well, Jab and I (mostly Jab) spent some time coming up with a work-around to make it work as expected.&lt;/p&gt;  &lt;pre class=&quot;xml&quot; name=&quot;code&quot;&gt;&amp;lt;ComboBox Grid.Row=&amp;quot;1&amp;quot; Margin=&amp;quot;0,14,0,0&amp;quot; Name=&amp;quot;comboBox1&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Width=&amp;quot;120&amp;quot;&lt;br /&gt;IsEditable=&amp;quot;False&amp;quot; KeyDown=&amp;quot;comboBox1_KeyDown&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;ComboBoxItem&amp;gt;Male&amp;lt;/ComboBoxItem&amp;gt;&lt;br /&gt;    &amp;lt;ComboBoxItem&amp;gt;Female&amp;lt;/ComboBoxItem&amp;gt;&lt;br /&gt;    &amp;lt;ComboBoxItem&amp;gt;Unknown&amp;lt;/ComboBoxItem&amp;gt;&lt;br /&gt;&amp;lt;/ComboBox&amp;gt;&lt;/pre&gt;&lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;private void comboBox1_KeyDown(object sender, KeyEventArgs e)&lt;br /&gt;{&lt;br /&gt;    ComboBox cb = sender as ComboBox;&lt;br /&gt;    if (e.Key == Key.Tab &amp;amp;&amp;amp; cb.IsDropDownOpen)&lt;br /&gt;    {&lt;br /&gt;        ComboBoxItem item = FocusManager.GetFocusedElement(Window.GetWindow(this)) as ComboBoxItem;&lt;br /&gt;        cb.SelectedItem = item;&lt;br /&gt;        cb.IsDropDownOpen = false;&lt;br /&gt;        e.Handled = true;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;It&#39;s not pretty, but it gets the job done.&amp;#160; Normally, I wouldn&#39;t have wasted time on this, but we really needed the tab functionality for an autocomplete box we&#39;re working on (hopefully we&#39;ll post some snippets of that soon).&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://rndnext.blogspot.com/feeds/7976744021317294947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rndnext.blogspot.com/2008/12/selecting-wpf-comboboxitem-with-tab-key.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7976744021317294947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/953670387080576871/posts/default/7976744021317294947'/><link rel='alternate' type='text/html' href='http://rndnext.blogspot.com/2008/12/selecting-wpf-comboboxitem-with-tab-key.html' title='Selecting a WPF ComboBoxItem with the Tab Key'/><author><name>Caleb</name><uri>http://www.blogger.com/profile/17381078593274483420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpumNVSZqjfJHLwfxQWu5Saq21-Lm6DwmvGNWf1hgT_vUMf3Ea0ylq3NYOHikrumDmJ7Kpz1wjPj436DK78aR0rFDddfS8i3CeKAo7R1SnqOlDOk_KpaI9sYs174rQw0w/s220/caleb.jpg'/></author><thr:total>0</thr:total></entry></feed>