<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.atalasoft.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Lou Franco's Software Business Blog : Programming</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx</link><description>Tags: Programming</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>If Google Can’t Make a Great Mobile Web App, Can Anyone?</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx</link><pubDate>Mon, 31 Aug 2009 11:45:45 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19227</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/19227.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=19227</wfw:commentRss><description>&lt;p&gt;I recently switched from NewsGator to Google Reader for reading RSS subscriptions, and along with that, I had to switch from a native iPhone app to using the iPhone version of Google Reader’s web application.&lt;/p&gt;  &lt;p&gt;The full-size Google Reader is one of the best web applications that I use – it’s just as good as GMail or Google Maps in terms of usability, responsiveness, and feature-set. The mobile version is very similar. It’s been optimized for iPhone, of course, but it’s a comparable to the normal site – they haven’t compromised much.&lt;/p&gt;  &lt;p&gt;Even so, on the iPhone, I wish they had made a native application instead. &lt;/p&gt;  &lt;p&gt;Here are some of the reasons why:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;On my iPhone, I don’t always have a great connection. I don’t feel the sluggishness of web applications on my PC, but on my iPhone, it’s pretty slow when I’m not on WiFi.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;iPhone native apps have consistent GUIs, and Reader really stands out like a sore thumb. One simple example is that navigation buttons aren’t always visible. Good desktop applications are more usable than web applications as well, but the margin is much wider on a mobile device. The native controls and look-and-feel are designed to work well on a mobile device, and it's not easy to duplicate that with HTML.     &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Deployment and updating are not issues on the iPhone. I’d be annoyed if I had to keep upgrading a native Reader application on my PC, but on the iPhone, it’s not really an issue. It’s automatic and fast – so I don’t have a natural preference for web applications like I do on my PC.     &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Having Reader share state with Safari is annoying. This might just be me, but I have more than one GMail login (personal and work) and every time I log out, it logs me out of Reader. I don’t have this issue as much on a PC because I can use multiple browsers, and I don’t switch as much on a single computer.     &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;No offline mode. I assume that they could do this if they want, since mobile Safari has an offline data store. With native applications, it’s just normal that they would still work offline. I think it’s reasonable to expect an RSS reader to have some caching.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I just switched, so I haven’t taken a look at the native RSS apps that support Google Reader. On first look, the Google mobile version looked like it would be good enough, but even the best mobile web applications don’t stand a chance against native applications.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;;subject=If+Google+Can%e2%80%99t+Make+a+Great+Mobile+Web+App%2c+Can+Anyone%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;;title=If+Google+Can%e2%80%99t+Make+a+Great+Mobile+Web+App%2c+Can+Anyone%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;title=If+Google+Can%e2%80%99t+Make+a+Great+Mobile+Web+App%2c+Can+Anyone%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;;title=If+Google+Can%e2%80%99t+Make+a+Great+Mobile+Web+App%2c+Can+Anyone%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx&amp;amp;;title=If+Google+Can%e2%80%99t+Make+a+Great+Mobile+Web+App%2c+Can+Anyone%3f&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/08/31/if-google-can-t-make-a-great-mobile-web-app-can-anyone.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19227" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/mobile/default.aspx">mobile</category></item><item><title>Computational Information Design</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx</link><pubDate>Wed, 06 May 2009 14:18:26 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:18422</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/18422.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=18422</wfw:commentRss><description>&lt;p&gt;Last night, &lt;a href="http://atalasoft.com"&gt;Atalasoft&lt;/a&gt; and &lt;a href="http://snowtide.com"&gt;Snowtide Informatics&lt;/a&gt; sponsored a meeting of the &lt;a href="http://wmassdevs.com"&gt;Western Mass Developers Group&lt;/a&gt;, which featured &lt;a href="http://benfry.com"&gt;Ben Fry&lt;/a&gt; speaking about Computational Information Design and the &lt;a href="http://processing.org"&gt;Processing&lt;/a&gt; programming language. O’Reilly also pitched in by giving us a few copies of Ben’s book, &lt;a href="http://oreilly.com/catalog/9780596514556/"&gt;Visualizing Data&lt;/a&gt;, to give away.&lt;/p&gt;  &lt;p&gt;The talk was a fascinating journey through Computational Information Design, an interdisciplinary field that encompasses aspects of Computer Science, Mathematics, Statistics, Graphic Design, User Experience Design, and Human Factors Engineering. &lt;em&gt;Visualizing Data&lt;/em&gt; goes into more depth, and you can see his early work describing this in his &lt;a href="http://benfry.com/phd/dissertation-050312b-acrobat.pdf"&gt;dissertation&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The main crux is that the process of data visualization has these steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;acquire&lt;/strong&gt; – the matter of obtaining the data, whether from a file      &lt;br /&gt;on a disk or from a source over a network.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;parse&lt;/strong&gt; – providing some structure around what the data means,      &lt;br /&gt;ordering it into categories.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;filter&lt;/strong&gt; – removing all but the data of interest.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;mine&lt;/strong&gt; – the application of methods from statistics or datamining, as a way to discern patterns or place the data in mathematical      &lt;br /&gt;context.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;represent&lt;/strong&gt; – determination of a simple representation, whether      &lt;br /&gt;the data takes one of many shapes such as a bar graph, list, or      &lt;br /&gt;tree.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;refine&lt;/strong&gt; – improvements to the basic representation to make it      &lt;br /&gt;clearer and more visually engaging.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;interact&lt;/strong&gt; – the addition of methods for manipulating the data or      &lt;br /&gt;controlling what features are visible.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Each of these steps require skills from traditionally different fields – and&amp;#160; Computational Information Design unites them. &lt;/p&gt;  &lt;p&gt;A key aspect of his work is the development of Processing, a programming language designed to be accessible to non-programmers, but powerful if needed. It has many simple abstractions to make graphics and interaction programming very simple, and can export to an Applet or Application for easy distribution. Much of his talk was dedicated to showing us some of the visualizations that have been created using it, including some that interact with the real-world in interesting ways. Works ranged from DNA visualizers, to book edition differencers and algorithmic art. &lt;a href="http://www.openprocessing.org"&gt;OpenProcessing&lt;/a&gt; has many examples with full source code.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;;subject=Computational+Information+Design" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;;title=Computational+Information+Design" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;title=Computational+Information+Design" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;;title=Computational+Information+Design" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx&amp;amp;;title=Computational+Information+Design&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2009/05/06/computational-information-design.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=18422" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Atalasoft/default.aspx">Atalasoft</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Code 39 Barcode Generation</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx</link><pubDate>Mon, 24 Mar 2008 13:37:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13536</guid><dc:creator>loufranco</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/13536.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=13536</wfw:commentRss><description>&lt;p&gt;I read this kind of funny story about a kid who got himself into a little trouble &lt;a href="http://davis.remmel.googlepages.com/drawingbarcodesbyhand"&gt;reading and writing barcodes by hand&lt;/a&gt;. After reading it, I figured if he's going through the trouble of getting graph paper and markers to write Code 39, I can certainly provide the code to doing it with DotImage.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_39"&gt;Code 39 is a simple barcode format&lt;/a&gt; -- it supports only capital letters, numbers, and seven other special characters (so 43 characters total). Each letter is encoded with nine alternating black and white bars, always starting and ending with black. Three of the nine bars will be wide, and the rest narrow (thus the name -- sometimes also called 3 of 9). Between each letter is a narrow white bar, and there is a start and stop code so you know that you are looking at a Code 39.&lt;/p&gt;

&lt;p&gt;One nice thing about Code 39 is that you can calculate the size in pixels before encoding, since each letter is the same size (3 wide and 6 narrow).&lt;/p&gt;

&lt;p&gt;Here's some code:&lt;/p&gt;

&lt;p&gt;First I grabbed the table of encodings from the wikipedia page on Code 39 and put them into a hashtable:&lt;/p&gt;
&lt;div style="margin-left:40px;font-family:courier;"&gt;private static Hashtable _encoding = new Hashtable();&lt;/div&gt;
&lt;p style="margin-left:40px;font-family:courier;"&gt;static BarcodeCode39()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _encoding['*'] = "bWbwBwBwb";&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _encoding['-'] = "bWbwbwBwB";&lt;/p&gt;

&lt;p style="margin-left:40px;font-family:courier;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // rest of encodings removed&amp;nbsp;&lt;/p&gt;

&lt;p style="margin-left:40px;font-family:courier;"&gt;}&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Here is how you calculate the width of the image (there are two extra characters added to the barcode, and I have a margin as well).&lt;/p&gt;

&lt;p style="font-family:courier;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public int ImageWidth&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return (_data.Length + 2) * ((3 * _wideWidth) + (6 * _narrowWidth)) + &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; (_data.Length+1) * _narrowWidth + &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; 2 * _margin;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;To make the barcode, I create the image:&lt;/p&gt;

&lt;p style="font-family:courier;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int imageWidth = ImageWidth;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AtalaImage barcodeImg = new AtalaImage(imageWidth, _imageHeight, pf, Color.White);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Canvas barcodeCanvas = new Canvas(barcodeImg);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Fill fill = new SolidFill(Color.Black);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AtalaPen pen = new AtalaPen(Color.Black); &lt;br&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;p&gt;Then here is my main loop through the data to encode: &lt;br&gt;&lt;/p&gt;

&lt;p style="font-family:courier;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // add start/stop&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string dataToEncode = "*" + _data + "*"; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int x = _margin;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (char c in dataToEncode) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; string bars = (string)_encoding[c];&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if (bars == null) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; throw new NotSupportedException("Invalid character in data: '"+c+"'");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (char b in bars) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; switch (b) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; case 'B': // Wide Black&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; barcodeCanvas.DrawRectangle(new Rectangle(x, _margin, _wideWidth, _imageHeight-2*_margin), pen, fill);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; x += _wideWidth;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; case 'W': // Wide White&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; x += _wideWidth;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; case 'b': // Narrow Black&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; barcodeCanvas.DrawRectangle(new Rectangle(x, _margin, _narrowWidth, _imageHeight-2*_margin), pen, fill);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; x += _narrowWidth;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; case 'w': // Narrow White&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x += _narrowWidth;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; x += _narrowWidth; // between characters&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;
I attached Assemblies built off of DotImage 6.0 -- if you have a maintenance release (you are reading this after 6.0a has been released), you can find a version of this in the Demo directories.&lt;/p&gt;

&lt;p&gt;Here's how you use it:&lt;/p&gt;

&lt;p style="font-family:courier;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BarcodeCode39 bc39 = new BarcodeCode39(data);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; bc39.Margin = 1;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AtalaImage img = bc39.CreateBarcodeImage(PixelFormat.Pixel24bppBgr); &lt;/p&gt;

&lt;p&gt;Then, you can use the image to overlay onto another with OverlayCommand. There are properties to adjust the outcome (NarrowWidth, WideWidth, ImageHeight, Margin).&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Here's how you recognize that barcode with the Atalasoft Barcode Reader:&lt;/p&gt;
&lt;p style="font-family:courier;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; BarReader br = new BarReader(img);&lt;br&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ReadOpts opts = new ReadOpts();&lt;br&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; opts.Symbology = Symbologies.Code39;&lt;br&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; BarCode[] bc = br.ReadBars(opts);&lt;br&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;;subject=Code+39+Barcode+Generation" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;;title=Code+39+Barcode+Generation" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;title=Code+39+Barcode+Generation" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;;title=Code+39+Barcode+Generation" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx&amp;amp;;title=Code+39+Barcode+Generation&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/03/24/code-39-barcode-generation.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13536" width="1" height="1"&gt;</description><enclosure url="http://www.atalasoft.com/cs/blogs/loufranco/attachment/13536.ashx" length="7863" type="application/zip" /><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/ECMi/default.aspx">ECMi</category></item><item><title>Clojure Presentation In Northampton</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx</link><pubDate>Wed, 27 Feb 2008 15:13:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13347</guid><dc:creator>loufranco</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/13347.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=13347</wfw:commentRss><description>&lt;P&gt;On March 20th, the regular meeting of the Western Mass Developer's Group will feature Rich Hickey, the author of Clojure.&lt;/P&gt;
&lt;P&gt;Clojure is a dialect of Lisp that compiles to Java Bytecode and runs on the JVM. It features persistent, immutable data structures and a model for creating multi-threaded designs. If you haven't seen clojure, please take a look at the site: &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; &lt;A href="http://clojure.sourceforge.net/"&gt;http://clojure.sourceforge.net/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The meeting will be at &lt;A class="" title="Map to 243 King St, Northampton" href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;q=243+King+Street,+Northampton+MA,+01060&amp;amp;sll=37.0625,-95.677068&amp;amp;sspn=38.554089,79.189453&amp;amp;ie=UTF8&amp;amp;ll=42.330171,-72.633448&amp;amp;spn=0.008804,0.019333&amp;amp;z=16&amp;amp;iwloc=addr"&gt;243 King Street in Northampton&lt;/A&gt; and will start at 6:30.&lt;/P&gt;
&lt;P&gt;And, if you have a chance, you might want to check out his talk at the Lisp NYC meeting:&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;A href="http://lispnyc.org/wiki.clp?page=past-meetings"&gt;http://lispnyc.org/wiki.clp?page=past-meetings&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;;subject=Clojure+Presentation+In+Northampton" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;;title=Clojure+Presentation+In+Northampton" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;title=Clojure+Presentation+In+Northampton" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;;title=Clojure+Presentation+In+Northampton" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx&amp;amp;;title=Clojure+Presentation+In+Northampton&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/27/clojure-presentation-in-northampton.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13347" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>AJAX v. Flash: Another Datapoint</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx</link><pubDate>Tue, 26 Feb 2008 02:27:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13317</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/13317.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=13317</wfw:commentRss><description>&lt;P&gt;Last week, &lt;A class="" href="http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/20/why-ajax-for-document-viewing.aspx"&gt;I wondered why Scribd uses Flash instead of AJAX&lt;/A&gt; and mentioned that it wouldn't work on my iPhone. Today I read that &lt;A class="" title="Debian removes Flash" href="http://www.us.debian.org/News/2008/20080217"&gt;Debian has removed flash from their distribution&lt;/A&gt;. Sure, the number of Debian installations won't even&amp;nbsp;show up in the 3rd decimal place of Flash penetration, but it would be shocking to hear a similar story about AJAX on any platform.&lt;/P&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;;subject=AJAX+v.+Flash%3a+Another+Datapoint" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;;title=AJAX+v.+Flash%3a+Another+Datapoint" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;title=AJAX+v.+Flash%3a+Another+Datapoint" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;;title=AJAX+v.+Flash%3a+Another+Datapoint" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx&amp;amp;;title=AJAX+v.+Flash%3a+Another+Datapoint&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/25/ajax-v-flash-another-datapoint.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13317" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Business of Software Conference</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx</link><pubDate>Sun, 24 Feb 2008 14:15:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13305</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/13305.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=13305</wfw:commentRss><description>&lt;P&gt;The 2nd annual &lt;A class="" href="http://www.businessofsoftware.org/"&gt;Business of Software Conference&lt;/A&gt; will be in Boston in the Fall. The conference is a off-shoot of the very popular &lt;A class="" href="http://discuss.joelonsoftware.com/?biz"&gt;BoS Forum on JoelOnSoftware&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;The site has videos up from last year's conference. I found this one on&amp;nbsp;measuring your code's (ahem) &lt;A class="" href="http://video.google.com/videoplay?docid=3217540637672747357&amp;amp;hl=en-GB"&gt;Change Risk Analysis and Predictions&lt;/A&gt;, to be particularly good.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;EMBED id=VideoPlayback style="WIDTH:400px;HEIGHT:326px;" src=http://video.google.com/googleplayer.swf?docId=3217540637672747357&amp;amp;hl=en-GB type=application/x-shockwave-flash flashvars=""&gt; &lt;/EMBED&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;;subject=Business+of+Software+Conference" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;;title=Business+of+Software+Conference" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;title=Business+of+Software+Conference" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;;title=Business+of+Software+Conference" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx&amp;amp;;title=Business+of+Software+Conference&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/24/business-of-software-conference.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13305" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Stream-Oriented Programming in PowerShell</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx</link><pubDate>Mon, 18 Feb 2008 21:12:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13251</guid><dc:creator>loufranco</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/13251.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=13251</wfw:commentRss><description>&lt;p&gt;While preparing my PowerShell presentation a few weeks ago, I was reminded of this &lt;a class="" title="Google Video: SICP Lectures on Stream Processing" href="http://video.google.com/videoplay?docid=5027109508195567041&amp;amp;q=stream+sicp&amp;amp;total=1&amp;amp;start=0&amp;amp;num=10&amp;amp;so=0&amp;amp;type=search&amp;amp;plindex=0"&gt;explanation of stream processing from the SICP lectures&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;object height="355" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/RcPhdoL8RcE&amp;amp;rel=1"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;embed type="application/x-shockwave-flash" wmode="transparent" width="425" height="355" src="http://www.youtube.com/v/RcPhdoL8RcE&amp;amp;rel=1"&gt;&lt;/object&gt;&lt;/p&gt;&lt;p&gt;This concept is widely used in Unix shells, but is really taken to the next level in PowerShell. In fact, after using it for a while, Unix style text stream processing seems primitive in comparison.&lt;/p&gt;&lt;p&gt;In PowerShell, commands emit streams of objects. When you use a pipe to connect commands, each object on the output of the first command is sent to the next one -- not a string representation, but the object itself. Since PowerShell is essentially a .NET reflection-based object automator -- most of this happens in-process (no serializing).&lt;/p&gt;&lt;p&gt;And, writing commands in .NET is simple -- I used &lt;a class="" title="Amazon link to PowerShell Cookbook, by Lee Holmes" href="http://www.amazon.com/Windows-PowerShell-Cookbook-Exchange-2007/dp/0596528493/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1203369940&amp;amp;sr=1-1"&gt;O'Reilly's PowerShell Cookbook, by Lee Holmes&lt;/a&gt; (highly recommended) to learn how -- but essentially, a cmdlet is a simple class that implements &lt;a class="" title="Cmdlet API" href="http://msdn2.microsoft.com/en-us/library/system.management.automation.cmdlet.aspx"&gt;System.Management.Automation.Cmdlet&lt;/a&gt;. Your public properties are automatically turned into command-line arguments (with one, optionally coming from the pipe), and then all you need to do is implement ProcessRecord(), which will be called for each input object. PowerShell manages the pipeline -- you just need to worry about one object at a time.&lt;/p&gt;&lt;p&gt;It's a powerful concept, but to fully take advantage of it, you'll need to wrap your OO designed objects in Cmdlets.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;;subject=Stream-Oriented+Programming+in+PowerShell" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;;title=Stream-Oriented+Programming+in+PowerShell" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;title=Stream-Oriented+Programming+in+PowerShell" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;;title=Stream-Oriented+Programming+in+PowerShell" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx&amp;amp;;title=Stream-Oriented+Programming+in+PowerShell&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/02/18/stream-oriented-programming.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13251" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Designing for Intellisense</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx</link><pubDate>Fri, 09 Nov 2007 13:28:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:12739</guid><dc:creator>loufranco</dc:creator><slash:comments>3</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/12739.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=12739</wfw:commentRss><description>&lt;P&gt;Atalasoft was at DevConnections this week, and I went to a some of the sessions including one on a deep dive of Linq, where I learned why Linq looks like this:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;CODE&gt;&lt;B&gt;from &lt;/B&gt;ord &lt;B&gt;in &lt;/B&gt;orders &lt;B&gt;select &lt;/B&gt;ord.id, ord.amount&lt;/CODE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Instead of this:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;CODE&gt;&lt;B&gt;select &lt;/B&gt;ord.id, ord.amount &lt;B&gt;from &lt;/B&gt;ord &lt;B&gt;in &lt;/B&gt;orders&lt;/CODE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The first example enables intellisense in the IDE to help you once you are finished with the from clause. I have to say, that I was a little shocked when he first said it. Up until then, I had filed this difference with SQL in the "Microsoft just has to be a little different" part of my brain that also knows when&amp;nbsp;to use backslashes and&amp;nbsp;where the menu bar is. &lt;/P&gt;
&lt;P&gt;The other thing that shocked me, is that I had never heard of a language feature that was specifically designed to be IDE-friendly. Certainly, there are features in languages that turn out that way. Having curly-braces helps&amp;nbsp;Visual Studio reformat your program, but C# doesn't have curly-braces for that reason (or maybe it does -- did K&amp;amp;R put curlies into C because of ed -- beats me).&amp;nbsp; In any case, if there's a language feature that exists just for the editor, I hadn't thought of it that way.&lt;/P&gt;
&lt;P&gt;It kind of got me thinking about method-calling syntax, which usually is&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;CODE&gt;object.method( ... )&lt;/CODE&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;but, in Ada and some languages it's&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;CODE&gt;method(object, ...)&lt;/CODE&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Which, until now, seemed to me to be an arbitrary choice, but with advanced editors, the first can actually be quite helpful. I guess the second would be good if I were more familiar with operations I could do and wanted the IDE to tell me which objects I could do them to, but that doesn't seem like the usual case to me.&lt;/P&gt;
&lt;P&gt;The idea of language features being designed for the IDE leads to the question of whether API's should be designed for the IDE as well. This comes up in DotImage when dealing with images and commands. In DotImage, we have an AtalaImage object that represents an image and an ImageCommand base class that image processing classes derive from. You use&amp;nbsp;commands like this:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;CODE&gt;
&lt;P&gt;AtalaImage img = new AtalaImage("image.jpg");&lt;BR&gt;ImageCommand cmd = new CropCommand(cropRect);&lt;BR&gt;ImageResults res = cmd.Apply(img);&lt;BR&gt;&lt;/P&gt;&lt;/CODE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;But, if you're new to our API, and you're wondering how to crop an image, you might want to type "img." and let the IDE pop up all of the choices. If you did, Crop would not be there. This makes sense, because we have over 150 commands, and we would not want to pollute AtalaImage with all of them. Also, if we made them methods, it would not be easy for our users to extend the API with their own commands that behave just like ours, and they wouldn't be able to inherit from the ones we have already. There are other reasons, like undo support and other features that operate on commands, but you get the point -- commands themselves&amp;nbsp;are interesting&amp;nbsp;enough&amp;nbsp;to be classes, not just methods on an image.&lt;/P&gt;
&lt;P&gt;C# 3.0 adds another feature for just that situation, &lt;A class="" href="http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx"&gt;Extension Methods&lt;/A&gt;, and now I'm starting to think that they exist just for intellisense too. The basic idea is that you make&amp;nbsp;static functions callable via dot syntax on an object if you make the first parameter the class of the object and mark it with "this". Continuing this example, a Crop method could be added to AtalaImage with this code:&lt;/P&gt;
&lt;P&gt;&lt;CODE&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static class AtalaImageCommands&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static ImageResults Crop(this AtalaImage img, Rectangle r)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new CropCommand(r).Apply(img);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;Now, I can call &lt;CODE&gt;img.Crop(...)&lt;/CODE&gt; as long as the namespace with this class is imported, and the IDE will show Crop as a method as well. The other nice thing is that anyone extending the library can add extension methods too (so their commands would work like the built-in ones).&lt;/P&gt;
&lt;P&gt;I'm not saying that we'll definitely use this (150 methods would still show up in the IDE), but choosing the 10 most used ones&amp;nbsp;might be a good idea.&amp;nbsp;Also, since you can control it by putting the extension methods in different namespaces, you can let the programmer decide&amp;nbsp;when they want them to show up. We could put extension methods for commonly used commands in the namespaces with the command classes, and put the rest in a sub-namespace.&lt;/P&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;;subject=Designing+for+Intellisense" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;;title=Designing+for+Intellisense" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;title=Designing+for+Intellisense" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;;title=Designing+for+Intellisense" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx&amp;amp;;title=Designing+for+Intellisense&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/11/09/designing-languages-for-the-ide.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=12739" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Atalasoft/default.aspx">Atalasoft</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Seven Tips for More Effective GUI Tests</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx</link><pubDate>Mon, 31 Jul 2006 18:45:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:10574</guid><dc:creator>loufranco</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/10574.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=10574</wfw:commentRss><description>One of the things I did for our new 4.0 release was write some GUI tests with &lt;a href="http://www.automatedqa.com"&gt;AutomatedQA's TestComplete&lt;/a&gt; for our new and improved &lt;a href="/products/dotimage/thinclient/"&gt;AJAX Image Viewer and Thumbnail Viewer&lt;/a&gt;. Along the way I learned a lot about how to write and maintain automated GUI scripts that I'd like to share. This is not a review of TestComplete -- I'm sure these tips would be applicable to any GUI scripting solution.&lt;br&gt;&lt;br&gt;For those not familiar with products like this, TestComplete allows you to record and playback GUI events and then compare screenshots against the original run. It's analogous to the role NUnit plays in unit testing, but with specific features to drive a GUI. We are using the web product which allows us to address the DOM inside a page shown in IE for fine grain access to the controls of the GUI. &lt;br&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt; &lt;b&gt;"Write" tests rather than record them. &lt;/b&gt;When you are just getting started with the tool, you're going to record tests and play them back, just to see how it works.&amp;nbsp; It's extremely important that you break yourself out of that habit as soon as possible and start writing scripts directly.&amp;nbsp; Otherwise you'll have scripts that look like this:&lt;br&gt;&lt;code&gt;&lt;br&gt;
&lt;b&gt;&lt;font color="#0000ff"&gt;function &lt;/font&gt;&lt;/b&gt;Test1()&lt;br&gt;{&lt;br&gt;&amp;nbsp; &lt;b&gt;&lt;font color="#0000ff"&gt;var&amp;nbsp; &lt;/font&gt;&lt;/b&gt;w1;&lt;br&gt;&amp;nbsp; &lt;b&gt;&lt;font color="#0000ff"&gt;var&amp;nbsp; &lt;/font&gt;&lt;/b&gt;w2;&lt;br&gt;&amp;nbsp; &lt;br&gt;&amp;nbsp; w1 = Sys["Process"]("iexplore")["Window"]("IEFrame", "*");&lt;br&gt;&amp;nbsp; w2 = w1["Window"]("Shell DocObject View")["Window"]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ("Internet Explorer_Server");&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp; w2["ToURL"]("http://localhost/ThinClientViewerTests/");  &lt;br&gt;&amp;nbsp; w2["Wait"]();&lt;br&gt;&amp;nbsp; w1 = w2["Page"]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ("http://localhost/ThinClientViewerTests/")["document"];&lt;br&gt;&amp;nbsp; w1["all"]["Item"]("DropDown_MouseTool")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ["ClickItem"]("Selection");&lt;br&gt;&amp;nbsp; w1["frames"]["frame"]("WebImageViewerMain_ov")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ["document"]["all"]["Item"](6)["Drag"](77, 86, 354, 254);&lt;br&gt;&amp;nbsp; &lt;b&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/b&gt;(!Regions.Compare("AfterSelection.bmp",&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Sys["Process"]("iexplore")["Window"]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ("IEFrame", "*")["Window"]("Shell DocObject View")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ["Window"]("Internet Explorer_Server")["Page"]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ("http://localhost/ThinClientViewerTests/")&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ["document"]["all"]["Item"]("WebImageViewerMain_om")))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Log.Error("The regions are not identical.");&lt;br&gt;}&lt;br&gt;&amp;nbsp;&lt;/code&gt;&lt;br&gt;instead of this:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;b&gt;&lt;font color="#0000ff"&gt;function &lt;/font&gt;&lt;/b&gt;TestSelection ()&lt;br&gt;{&lt;br&gt;&amp;nbsp; &lt;b&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;/b&gt;w = GetIEProcess();&amp;nbsp;&amp;nbsp; &lt;br&gt;&amp;nbsp; GotoTestPage(w);&lt;br&gt;&amp;nbsp; &lt;br&gt;&amp;nbsp; &lt;b&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;/b&gt;doc = GetDocument(w, GetUrl());&lt;br&gt;&amp;nbsp; &lt;br&gt;&amp;nbsp; ChooseMouseTool(doc, "Selection");&lt;br&gt;&amp;nbsp; GetImage(doc)["Drag"](77, 86, 354, 254);&lt;br&gt;&amp;nbsp; AssertRegionIsEqual("AfterSelection.bmp",&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GetImageViewerControl(doc));&lt;br&gt;}&lt;br&gt;&lt;/code&gt;&lt;br&gt;Granted, you're likely to want to rewrite the recorded code a little bit, but I'm advocating a full refactoring so that the scripts share as much code as possible. Once you've done this a few times, you will find yourself just writing the tests directly instead of recording them. Some of the following tips are only possible if you take this step.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt; Make tests resilient to change. &lt;/b&gt;One of the most frustrating aspects to GUI testing is that the look and components of the GUI are not stable until late in the development cycle. They are also more likely to change in a new version than software APIs, for which we have developed many practices and patterns to make them backwards compatible. Changes in a GUI, by their nature, are not compatible at the level we need for an automated test, so you must make your tests easy to update. There are two things you should do:&lt;br&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Take snapshots carefully&lt;/b&gt;. Do not take a full window screenshot to compare unless it is necessary -- instead take a snapshot of the relevant area.&amp;nbsp; If this part of the window moves around, most tools will know how to find it (they poke into the underlying form, or in my case, DOM, to find its location on the screen). If your tool supports it, use its image comparison tolerance and masking features to compare just the important parts.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Access controls through accessor functions&lt;/b&gt;. Each piece of the GUI that you control or snapshot should be accessed via a function that you write.&amp;nbsp; That way, if its name changes, or if something has to be done before accessing it, you have a hook. If you've refactored the recorded scripts, you're probably already doing this.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Make failures easy to figure out.&lt;/b&gt; The easiest way to do this is to log breadcrumbs along the way.&amp;nbsp; Again this is easy to do if you've refactored code. In my case, &lt;code&gt;AssertRegionIsEqual&lt;/code&gt; logs what it is comparing so that I know how to interpret any failures.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt; Make tests individually callable.&lt;/b&gt; In TestComplete, this means making each test function void and taking no arguments. This is the default when recording them, but when I was rewriting them, it was very tempting to try to make them OO or add arguments. This makes it hard to just right click on one and choose "Run" from the context menu, which I consider a must-have feature. So, even though the code could be better organized, I won't do it if the tests can't be called from the editor.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt; &lt;b&gt;Have the tests put the GUI into known states&lt;/b&gt;. One thing I noticed early on is that I'd sometimes have an image comparison error because a control had the mouse over it or the control had focus when playing back, but not during the snapshot. This is because the snapshot tool requires you to move the mouse and take focus away, but playback does not. It's important to put the mouse exactly where you want it and give focus to a control or area that won't change it's look (by clicking the background, e.g.) before you take a snapshot.&amp;nbsp; Once I realized this, I wrote a function to do it and called it in my snapshot comparison function.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Write focused tests.&lt;/b&gt; Do not have one giant function that &lt;span&gt;exercises &lt;/span&gt;your entire GUI. Break it down into individual, stand-alone tests.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;If you use a bug-tracker, write GUI tests to confirm a fix.&lt;/b&gt; While developing, it great to test-first and write an automated unit test that reproduces a bug before you fix it.&amp;nbsp; While confirming those fixed bugs (in acceptance testing), it is equally important to write a repeatable test that confirms that the bug is fixed. Of course, you should comment the case number in the test script and the script name in your bug-tracker.&lt;/li&gt;&lt;/ol&gt;In general, I find it's harder to make a reliable repeatable GUI test than a Unit test. Having a maintainable code base makes it possible to add in code later that makes it more reliable. Also, it's easy for me to to change my code from a testing script to a snapshotting one, when I want to make a different snapshot repository for different initial conditions (in my case for when the image viewer is viewing a different test image). These things would be impossible if I didn't rewrite the recorded script, which I think is the key to making tools like these more useful.  &lt;br&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;;subject=Seven+Tips+for+More+Effective+GUI+Tests" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;;title=Seven+Tips+for+More+Effective+GUI+Tests" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;title=Seven+Tips+for+More+Effective+GUI+Tests" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;;title=Seven+Tips+for+More+Effective+GUI+Tests" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx&amp;amp;;title=Seven+Tips+for+More+Effective+GUI+Tests&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/07/31/10574.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=10574" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Atalasoft/default.aspx">Atalasoft</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Atalasoft in 3D</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx</link><pubDate>Wed, 10 May 2006 20:52:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:10029</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/10029.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=10029</wfw:commentRss><description>Part of what I'm doing puts me knee-deep in Atalasoft
ImageCommands.&amp;nbsp; I was staring at some results of TintGrayscale and
wondered how easy it would be to make the kind of 3D images that are a
combined red and blue images with Atalasoft dotImage. Turns out, it's
really easy.&lt;br&gt;&lt;br&gt;Here is what you need to do:&lt;br&gt;&lt;br&gt;1. Take two pictures of a subject with the camera shifted three inches horizontally.&lt;br&gt;
&lt;br&gt;2. Turn both images to grayscale&lt;br&gt;&lt;blockquote&gt;AtalaImage left = new AtalaImage(_leftName);&lt;br&gt;left = left.GetChangedPixelFormat(PixelFormat.Pixel8bppGrayscale);&lt;br&gt;&lt;br&gt;AtalaImage right = new AtalaImage(_rightName);&lt;br&gt;right = right.GetChangedPixelFormat(PixelFormat.Pixel8bppGrayscale);&lt;br&gt;&lt;/blockquote&gt;3.
Make a third image that uses AtalaImage.CombineChannels where the left
image is in channels one and two, and the right image is in channel
three.&lt;br&gt;&lt;blockquote&gt;_combinedChannelsImg = AtalaImage.CombineChannels(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PixelFormat.Pixel24bppBgr, new AtalaImage[] { left, left, right });&lt;br&gt;&lt;/blockquote&gt;4. Use ShiftChannelsCommand to correct for any offset errors that may have been introduced when the pictures were taken.&lt;br&gt;&lt;blockquote&gt;ShiftChannelsCommand lscc = new ShiftChannelsCommand(-hstep, -vstep,&amp;nbsp; &lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ChannelFlags.Channel3, 127);&lt;br&gt;ShiftChannelsCommand rscc = new ShiftChannelsCommand(hstep, vstep,&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
ChannelFlags.Channel1 | ChannelFlags.Channel2,
127);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
_combinedChannelsAndShiftedImg = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lscc.ApplyToImage(_combinedChannelsImg);&lt;br&gt;_combinedChannelsAndShiftedImg =&amp;nbsp; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rscc.ApplyToImage(_combinedChannelsAndShiftedImg);&lt;br&gt;&lt;/blockquote&gt;If you want to run an application built on this code, download the zip attached at the bottom of this post. I've included
a left and right image of our lounge in the zip to play with (Now supports .NET 1.1).&lt;br&gt;
&lt;ol&gt;
  &lt;li&gt;Click in the top left box and pick your left image&lt;/li&gt;
  &lt;li&gt;Click the top right box and pick your right image. &lt;/li&gt;
  &lt;li&gt;Click the Combine button.&lt;/li&gt;
  &lt;li&gt;Use the sliders if adjust the position of the channels if your
originals aren't aligned well (shouldn't be necessary for the lounge
pictures).&lt;/li&gt;
  &lt;li&gt;Click on the combined image to save it.&lt;br&gt;
  &lt;/li&gt;
&lt;/ol&gt;
You need 3D glasses to see the effect (right eye red, left eye blue).&lt;br&gt;&lt;br&gt;&lt;b&gt;Update: &lt;/b&gt;The resulting image&lt;br&gt;&lt;br&gt;&lt;a href="/cs/photos/images/picture10033.aspx" target="_blank"&gt;&lt;br&gt;&lt;/a&gt;&lt;a href="/cs/photos/images/picture10033.aspx" target="_blank"&gt;&lt;br&gt;&lt;/a&gt;&lt;a href="/cs/photos/images/picture10033.aspx" target="_blank"&gt;&lt;img src="/cs/photos/images/images/10033/secondarythumb.aspx" border="0"&gt;&lt;/a&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;;subject=Atalasoft+in+3D" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;;title=Atalasoft+in+3D" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;title=Atalasoft+in+3D" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;;title=Atalasoft+in+3D" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx&amp;amp;;title=Atalasoft+in+3D&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/05/10/Lou-Franco.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=10029" width="1" height="1"&gt;</description><enclosure url="http://www.atalasoft.com/cs/blogs/loufranco/attachment/10029.ashx" length="2901644" type="application/x-zip-compressed" /><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Atalasoft/default.aspx">Atalasoft</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>On Optimizing: Tips for the inner loop</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx</link><pubDate>Fri, 28 Apr 2006 11:56:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:9985</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/9985.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=9985</wfw:commentRss><description>Everyone knows the first two rules of optimizing: (1) Don't pre-optimize, and (2) Use a profiling tool to make sure you spend time optimizing the right code. I mostly agree with (1) -- I'll get back to that in a bit, and nothing beats a good profiling tool. We use &lt;a href="http://automatedqa.com/products/aqtime"&gt;AQTime&lt;/a&gt; here, and it's .NET integration and seamless support of both managed and unmanaged code is a big help when you're writing fast algorithms in unmanged code with a managed wrapper.&lt;br&gt;&lt;br&gt;Another pearl of wisdom is "blah blah blah is fast enough (unless you're in a large nested loop)." Well, here at &lt;a href="http://www.atalasoft.com"&gt;Atalasoft&lt;/a&gt;, we do image processing, and practically everything you do is in a nested loop over all of the pixels of the image, so all of the sudden, nothing is "fast enough". All of the sudden, you find yourself counting operations and conditionals, removing all floating-point, any division and as much of anything else that you can.&lt;br&gt;&lt;br&gt;Here are some tips if you find yourself needing to optimize an inner loop. These tips are for C/C++, because if you are even thinking of doing this, you want to be in unmanaged land (one of the reasons why not pre-optimizing can get you into trouble -- choosing the right technology for when you need speed, is an important first step).&lt;br&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Use integers&lt;/b&gt;. Modern instruction sets mean that naive compilation of C to machine code results in similar speed for ints and double (my quick tests show doubles as faster), but turn optimization on, and it's a different story. My double code improved slightly, but my int code was three times faster when optimized. A quick look at the assembly showed that the code for doubles was similar, but for ints, it was transformational. Biggest difference was in using shifts for multiply and divide by a constant (I did not use powers of 2, but it figured out tricks anyway). Optimizers are better at improving calculations with ints than with doubles.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Don't divide&lt;/b&gt;. A corollary to using integers is that you can't divide without losing precision -- that's ok, it was probably slow anyway. A common reason to want to divide in image manipulation is for calculating ratios. In line drawing and scaling algorithms, watching a ratio is a way to know when the error term is large enough to move onto the next row or column. It often looks something like this:&lt;br&gt;&lt;br&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;if &lt;/font&gt;((xSrc+1)/wSrc &amp;gt; xDst/wDst) ++xSrc;&lt;/font&gt;&lt;br&gt;&lt;br&gt;You can't do this with ints, so cross multiply.&lt;br&gt;&lt;br&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;if &lt;/font&gt;((xSrc+1)*wDst &amp;gt; xDst*wSrc) ++xSrc;&lt;/font&gt;&lt;br&gt;&lt;br&gt;We aren't going to keep this either, but this step helps with the next one.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Don't mulitply&lt;/b&gt;. Often, in a loop, we're multiplying by the index. This can be replaced by an accumulation. The code above gets turned into this:&lt;br&gt;&lt;br&gt;&lt;font face="Courier New"&gt;xDst_Times_WSrc += wSrc;&lt;/font&gt;&lt;br&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;if &lt;/font&gt;(&lt;/font&gt;&lt;font face="Courier New"&gt;xSrc&lt;/font&gt;&lt;font face="Courier New"&gt;_Times_&lt;/font&gt;&lt;font face="Courier New"&gt;wDst_Plus_wDst&lt;/font&gt;&lt;font face="Courier New"&gt; &amp;lt;= &lt;/font&gt;&lt;font face="Courier New"&gt;xDst&lt;/font&gt;&lt;font face="Courier New"&gt;_Times_&lt;/font&gt;&lt;font face="Courier New"&gt;WSrc&lt;/font&gt;&lt;font face="Courier New"&gt;) {&lt;br&gt;&amp;nbsp;&amp;nbsp; ++xSrc;&lt;/font&gt;&lt;font face="Courier New"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier New"&gt;xSrc&lt;/font&gt;&lt;font face="Courier New"&gt;_Times_&lt;/font&gt;&lt;font face="Courier New"&gt;wDst_Plus_wDst&lt;/font&gt;&lt;font face="Courier New"&gt; += wDst;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Don't recalculate on each iteration&lt;/b&gt;.&amp;nbsp; The optimization above also gets a big boost from the fact that xSrc doesn't change every iteration (and therefore, &lt;font face="Courier New"&gt;(xSrc+1)*wDst&lt;/font&gt; doesn't either).&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Use Table lookups to replace costly calculations&lt;/b&gt;. This is a common technique.&amp;nbsp; Steve described it &lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/archive/2006/04/03/9869.aspx"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Replace array indexing with pointer incrementing&lt;/b&gt;. Table lookups are a multiplication and an addition, so it's not necessarily faster than a calculation at this level. But, often we are indexing by the inner loop index (because a calculation is the same for every row). In that case, increment a pointer into the table, rather than indexing.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Look for repeating patterns&lt;/b&gt;. Often a calculation results in a repeating pattern as you loop. If so, you can precalculate the table of results (just the smaller repeating section) outside the loop and then use a table lookup in the inner loop. This will be slower if there is no pattern, because you have to detect the pattern with a conditional.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;In my particular case, the biggest wins were with (4) and (7). The repeat size was often orders of magnitude smaller than the image width (and not a function of it), so the larger the image, the more the potential speedup, which meant my algorithm time grew much slower than the original. However, without rewriting the algorithm with (1), (2) and (3), it might not have been obvious how to apply them, and (7) without (6) would not have been as fast.&lt;br&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;;subject=On+Optimizing%3a+Tips+for+the+inner+loop" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;;title=On+Optimizing%3a+Tips+for+the+inner+loop" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;title=On+Optimizing%3a+Tips+for+the+inner+loop" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;;title=On+Optimizing%3a+Tips+for+the+inner+loop" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx&amp;amp;;title=On+Optimizing%3a+Tips+for+the+inner+loop&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/28/9985.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=9985" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item><item><title>XAML vs. The Humble Dialog Box</title><link>http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx</link><pubDate>Thu, 06 Apr 2006 15:20:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:9894</guid><dc:creator>loufranco</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/loufranco/comments/9894.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/loufranco/commentrss.aspx?PostID=9894</wfw:commentRss><description>&lt;a href="http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf"&gt;The Humble Dialog Box [pdf]&lt;/a&gt; is a pattern to separate UI behavior from code that deals with a specific view technology, like WPF. Essentially, for each window you have a UI data/behavior class, an abstract view class (or interface), and a concrete view for each different type of view you're supporting. The view class should have all view technology specific code and almost nothing else. Everything else should be routed to the behavior class.&lt;br&gt;&lt;br&gt;Each concrete view is responsible for rendering the information in the behavior class on demand and routing all inputs (keyboard, mouse, etc) to it. The behavior class has no public getters, so it's hard for the view to handle most events itself anyway. &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;Model View Presenter&lt;/a&gt; from Fowler's Patterns of Enterprise Application Architecture is essentially the same thing, and has a simple C# example.&lt;br&gt;&lt;br&gt;The simple steps (from the end of the Humble Dialog Box article) are:&lt;br&gt;&lt;blockquote&gt;&lt;ol&gt;&lt;li&gt;Create a class for the smart object, and an interface class for the view. Pass the view to the smart object&lt;/li&gt;&lt;li&gt;Develop commands against the smart object, test first. Write your tests against a mock view.&lt;/li&gt;&lt;li&gt;Create your dialog class and implement the view interface on it. Gestures on the dialog should delegate to commands on the smart object. Calls from the smart object to the dialog should resolve to simple setter methods.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;One obvious reason to do this is to support different views that have the same underlying behavior (perhaps differing only in layout). The reason I usually use it is to support a mock view to use in unit testing.&lt;br&gt;&lt;br&gt;This is not the same as the separation of behavior that you get with the XAML file and the code-behind (.xaml.cs) file, because the code file will still usually have some WPF specific code in it. That's ok, but it's not Humble Dialog Box. To get that you'd need to add an abstract superclass or interface to the code-behind file and a behavior class that you route all events to.&lt;br&gt;&lt;br&gt;The interesting cases are how you handle simple events in the view without routing them through the behavior class. For instance, if you have a list box on your window, you wouldn't want to route the mouse click on an item back to the behavior class so that it could change the selected item. Usually, you let the list box handle the mouse click and then route a selection changed event if needed. If the views don't dynamically change with the list box selection, you can just send the selection to the behavior class when the OK button is clicked.&lt;br&gt;&lt;br&gt;Sometimes the Humble Dialog Box is overkill, but if you have complex UI behavior that you want to unit test, it's pretty useful. It is with unit testing in mind that I want to explore some of the XAML features that deal with UI behavior, namely Triggers, Data Binding, and Animation.&lt;br&gt;&lt;br&gt;Triggers allow you to put simple event handlers right in your XAML. Here's a simple example that changes a button's background to yellow when the mouse is over them.&lt;br&gt;&lt;br&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;font color="#008000"&gt;Style&lt;/font&gt; &lt;font color="#800080"&gt;TargetType&lt;/font&gt;="{x:Type Button}"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;font color="#008000"&gt;Style.Triggers&lt;/font&gt;&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;font color="#008000"&gt;Trigger&lt;/font&gt; &lt;font color="#800080"&gt;Property&lt;/font&gt;="IsMouseOver" &lt;font color="#800080"&gt;Value&lt;/font&gt;="True"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;font color="#008000"&gt;Setter &lt;/font&gt;&lt;font color="#800080"&gt;Property&lt;/font&gt;="Background" &lt;font color="#800080"&gt;Value&lt;/font&gt;="Yellow"/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;font color="#008000"&gt;Trigger&lt;/font&gt;&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;font color="#008000"&gt;Style.Triggers&lt;/font&gt;&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;font color="#008000"&gt;Style&lt;/font&gt;&amp;gt;&lt;br&gt;&lt;br&gt;&lt;/code&gt;Triggers are great for these simple single-control behaviors, especially if they have no impact on the data model. If they get much more complex than this, then it will be hard to unit test. Also, if the behavior needs to be supported for non-XAML views, then it would be better to handle it outside of XAML. Any trigger that affects controls other than the one with the trigger is definitely suspect -- I'm not even sure how you do that, since the setters don't take an object anyway, but even if you can, I would stay away from that.&lt;br&gt;&lt;br&gt;Data Binding lets you automatically route events to a model object and propagate changes back to the view (by binding controls to events in the model). They are very close to the Humble Dialog, and perhaps good enough for most cases. The model classes are certainly testable, but in the simplest &lt;span&gt;implementations&lt;/span&gt;, you will still handle the event in the XAML code-behind class and then call setters on the model object.&lt;br&gt;&lt;br&gt;To be more like the Humble Dialog, the event handlers should just send the event to the model objects, which then calls setters on itself (raising PropertyChanged events to get the changes back to the view). Code in the xaml.cs file should refrain from calling the getters in the model class and operating on the results -- let the model's events tell you when to update.&lt;br&gt;&lt;br&gt;Animation is a complex enough behavior to want to unit test. However, the alternative to using XAML is not pretty, and the sheer amount of code savings and simplification you get by using XAML might outweigh the benefits you'd get from controlling animation outside of XAML in another class. My approach to unit testing animation would be to read the XAML into a test class and make some assertions on its structure (for instance to check coordinated timings).&lt;br&gt;&lt;br&gt;My first impression with WPF and XAML is that I would want to take advantage of its features, even if that meant making my UI's less testable--simplification is less error-prone, and code I don't need to write also doesn't need to be tested. &lt;br&gt;&lt;br&gt;Data Binding certainly supports unit testing of the model classes and it's easy to get to Humble Dialog from it. Animation and Triggers can be somewhat tested by asserting the contents of the XAML file. I will blog more as I explore these methods.&lt;br&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;;subject=XAML+vs.+The+Humble+Dialog+Box" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;;title=XAML+vs.+The+Humble+Dialog+Box" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;title=XAML+vs.+The+Humble+Dialog+Box" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;;title=XAML+vs.+The+Humble+Dialog+Box" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx&amp;amp;;title=XAML+vs.+The+Humble+Dialog+Box&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/04/06/9894.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=9894" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/WinFX/default.aspx">WinFX</category><category domain="http://www.atalasoft.com/cs/blogs/loufranco/archive/tags/Programming/default.aspx">Programming</category></item></channel></rss>