<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1801443688792449833</id><updated>2011-11-20T00:01:52.497+13:00</updated><category term='LINQ'/><category term='Usability'/><category term='Games'/><category term='Computer Science'/><category term='Visual Art'/><category term='Patterns and Practices'/><category term='General'/><category term='Travel'/><category term='User Experience'/><category term='Team Projects'/><category term='Software Development'/><category term='Music'/><category term='EPiServer'/><category term='Test-Driven Development'/><category term='CodeProject'/><category term='Hardware'/><category term='Design'/><category term='Tech-Ed'/><category term='WPF'/><category term='Workflow Foundation'/><category term='Silverlight'/><title type='text'>Tech &amp; Arts</title><subtitle type='html'>Tidbits on Software Development, Music &amp; Other Arts</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-478091446328336660</id><published>2011-11-08T13:54:00.006+13:00</published><updated>2011-11-08T15:40:35.658+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='General'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Art'/><title type='text'>Wellywood Controversy</title><content type='html'>For those who haven't been in touch with local Wellington news, part of the 'talk of the town' is the controversial 'Wellywood' sign, inspired by the well-known 'Hollywood' sign in L.A. (just switch 'Ho' with 'We' and bob's-your-uncle). &lt;a href="http://www.wellington-airport.co.nz/"&gt;Wellington International Airport Limited&lt;/a&gt; (WIAL) owns the land on the Miramar cutting, and decided it would be nice to put such a sign there.&lt;br /&gt;&lt;br /&gt;Several months later, they have resource consent and have twice announced they were putting up 'that' sign - both times to severe backlash from the general public. Fortunately the powers-that-be have taken this opposition on board and created &lt;a href="http://www.stuff.co.nz/dominion-post/news/wellywood-or-what/"&gt;a competition&lt;/a&gt; to come up with an alternative design, that more of us could be proud of.&lt;br /&gt;&lt;br /&gt;Naturally, I decided to take them up on the opportunity ;-)&lt;br /&gt;&lt;br /&gt;Firstly, the issues with the original proposal that I wanted to address were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A sense of 'tackiness' - taking a colloquial term coined through the media, to describe the local film industry catalysed through the work of Peter Jackson, Weta Workshop &amp;amp; Weta Digital, and giving that some sort of official status. While I have great respect for what these people have achieved, there is more to Wellington than the film industry to be proud of.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lack of originality - the font is exactly the same as the well-known Hollywood sign. 7/9 of the sign reads exactly the same.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A sense of 'me-too' desperation - Hollywood is an actual name of a suburb, they found their identity. Wellington has its own identity that we should nurture and develop, and it won't come from aping others and shouting for attention. That seems too 'try-hard', and gives me an impression that Wellington isn't confident in or proud of itself to stand on its own feet.&lt;/li&gt;&lt;/ul&gt;There were several main criteria for the submitted concepts, including: fit within a 27 x 3.5m area; not have protrusions more than 0.5m; no lighting or illumination; and realistically be constructed within an $80,000 budget. Concepts don't necessarily have to be a sign, but could also be an image or artwork.&lt;br /&gt;&lt;br /&gt;With that in mind, here's what I came up with:&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-qmN2XfIkFmI/TriK16wWDuI/AAAAAAAAAEk/MG7qUhJtEMk/s1600/Sign1_montage.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/-qmN2XfIkFmI/TriK16wWDuI/AAAAAAAAAEk/MG7qUhJtEMk/s400/Sign1_montage.jpg" alt="" id="BLOGGER_PHOTO_ID_5672436389582868194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;No 'Wellywood' - Wellington does just fine. Original, angular font, which complements the 'rock-face' texture. This texture also complements and draws inspiration from the interior of the 'rocks' international airport terminal, which has recently won the Transport category at the &lt;a href="http://www.insidefestival.com/news-detail.cfm?newsId=4"&gt;Inside Festival&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For those who don't see the link with the film industry, bear in mind that I created this using a 3D modeller called &lt;a href="http://www.blender.org/"&gt;Blender&lt;/a&gt; - which is similar to software that modellers use at Weta Digital. The black lines evoke a sense of a triangulated 3D mesh. I don't believe we need imagery of Gollum, King Kong, etc. to highlight this; also considering that such imagery would likely be under strict copyright from the respective studios.&lt;br /&gt;&lt;br /&gt;Here's another variation, with a slightly more futuristic font:&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-k1_zZpt3L5s/TriSoFWI3VI/AAAAAAAAAEw/P38kRQdt25o/s1600/Sign2_montage.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 391px; height: 400px;" src="http://3.bp.blogspot.com/-k1_zZpt3L5s/TriSoFWI3VI/AAAAAAAAAEw/P38kRQdt25o/s400/Sign2_montage.jpg" alt="" id="BLOGGER_PHOTO_ID_5672444948000595282" border="0" /&gt;&lt;/a&gt;In the end, over 350 submissions were received. Five were put forward as &lt;a href="http://www.stuff.co.nz/dominion-post/news/wellywood-or-what/5878116/Wellywood-voting-begins"&gt;the finalists&lt;/a&gt; for public vote. Yes, I can live with the fact that neither of mine were selected, but those finalists had better be good. Sadly, I was a little underwhelmed, and I wasn't alone. Someone commented, "Are our designers that inept?" Another commented, "I can't believe these are the five best from more than 300 entries! Let's see all the options listed."&lt;br /&gt;&lt;br /&gt;Well I hope I've proved the first commenter wrong, and whetted the appetite of the second.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-478091446328336660?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/478091446328336660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=478091446328336660' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/478091446328336660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/478091446328336660'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2011/11/wellywood-controversy.html' title='Wellywood Controversy'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-qmN2XfIkFmI/TriK16wWDuI/AAAAAAAAAEk/MG7qUhJtEMk/s72-c/Sign1_montage.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3927122303733477399</id><published>2010-03-09T22:09:00.003+13:00</published><updated>2010-03-10T00:07:30.916+13:00</updated><title type='text'>Regular Expressions: From Zero to Regex Hero</title><content type='html'>Last week I presented this session on Regular Expressions at the &lt;a href="http://www.dot.net.nz/UserGroupPages/WellingtonNET.aspx"&gt;Wellington .NET User Group&lt;/a&gt;. It was nice to get such a great reception from the audience, and I hope they were able to follow along with the content.&lt;br /&gt;&lt;br /&gt;Part of what made this a success was the integration of the technical demos in the presentation. From previous experience presenting at the &lt;a href="http://www.dot.net.nz/UserGroupPages/WellingtonSilverlight.aspx"&gt;Silverlight User Group&lt;/a&gt;, it can feel awkward having notes in the slides to jump to the demo, and conversely having to remember when to jump back into the slides without taking the demo too far. The task-switching also introduces the potential to inadvertently end the slide show and require paging through many slides to return to the proper point in the presentation.&lt;br /&gt;&lt;br /&gt;In the end, I drew inspiration from &lt;a href="http://bea.stollnitz.com/"&gt;Bea Stollnitz&lt;/a&gt;'s WPF presentations, where her slides are developed using &lt;a href="http://bea.stollnitz.com/blog/?p=49"&gt;WPF instead of PowerPoint&lt;/a&gt;. At it's heart, the application uses the Page-based navigation feature of WPF to display the slides.&lt;br /&gt;&lt;br /&gt;What I have done is integrate live controls that are able to test/demonstrate regular expressions into the particular slides, making it unnecessary to switch to the IDE. And if you do, the application can be restarted from the slide that was previously shown. A key difference from Bea's implementation is that I use the Model-View-ViewModel design pattern for a greater degree of separation between UI and content. This also allows more slides to be defined than there are distinct WPF Pages; binding to different viewmodels allows each template page to display different content. The real content of the slides (except 'fixed content' slides) is then defined in a single XML file.&lt;br /&gt;&lt;br /&gt;I have placed the source for this application, dubbed RegExpress, on CodePlex at &lt;a href="http://regexpress.codeplex.com/"&gt;http://regexpress.codeplex.com/&lt;/a&gt;. This requires Visual C# 2008 or later to build and run. A good spin-off is that aside from providing guidance through the features of regular expressions, RegExpress can also be used to prototype or test regular expressions for particular software tasks, e.g. input string validation, data extraction, and search &amp;amp; replace.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/S5YqzKR234I/AAAAAAAAAEE/sKq5f98g2pw/s1600-h/RegExpress.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 198px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/S5YqzKR234I/AAAAAAAAAEE/sKq5f98g2pw/s400/RegExpress.png" alt="" id="BLOGGER_PHOTO_ID_5446587857772142466" border="0" /&gt;&lt;/a&gt;Finally, for more detailed info on the inner workings of regular expressions, I highly recommend visiting &lt;a href="http://www.regular-expressions.info/"&gt;http://www.regular-expressions.info/&lt;/a&gt;. This is essentially the 'Bible' of Regular Expressions, and is great for walking through how regular expressions work behind-the-scenes. It is worth knowing about these details, as the understanding makes it easier to compose expressions on-the-fly to solve custom problems, or to determine why a particular expression might not be working properly.&lt;br /&gt;&lt;br /&gt;After all, there is often a case where regular expressions will help you &lt;a href="http://www.xkcd.com/208/"&gt;save the day&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3927122303733477399?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3927122303733477399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3927122303733477399' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3927122303733477399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3927122303733477399'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2010/03/regular-expressions-from-zero-to-regex.html' title='Regular Expressions: From Zero to Regex Hero'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PtRfH0rESBo/S5YqzKR234I/AAAAAAAAAEE/sKq5f98g2pw/s72-c/RegExpress.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3890255917985677743</id><published>2010-02-04T22:48:00.005+13:00</published><updated>2010-02-04T23:43:40.704+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Art'/><category scheme='http://www.blogger.com/atom/ns#' term='Computer Science'/><title type='text'>Visual Art Meets Maths / Computer Science</title><content type='html'>Recently our Auckland office had a new art installation on the wall of one of its meeting rooms. Being a technology company, it was quite apt to make it an array of dots that predictably spelt 'Intergen' in binary (albeit all-caps). Here's what it looks like below:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qiAwrv8DI/AAAAAAAAADU/LAM_82PRQSY/s1600-h/BinaryArtOriginal.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 363px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qiAwrv8DI/AAAAAAAAADU/LAM_82PRQSY/s400/BinaryArtOriginal.jpg" alt="" id="BLOGGER_PHOTO_ID_5434334034328023090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What I noticed, being uppercase, was that the first three bits were always the same - which is in stark contrast to the pattern formed by the remaining bits. Also noticing that the art was eight bytes (forming a square grid) gave me an idea: &lt;a href="http://en.wikipedia.org/wiki/Hilbert_curve"&gt;Hilbert curves&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Rather than serialising the bits across each row from top to bottom, these bits could be serialised along the path of a Hilbert curve. So how do we construct this Hilbert curve?&lt;br /&gt;&lt;br /&gt;A Hilbert curve is a &lt;a href="http://en.wikipedia.org/wiki/Fractal"&gt;fractal&lt;/a&gt; in similar vein to a &lt;a href="http://en.wikipedia.org/wiki/Koch_curve"&gt;Koch curve&lt;/a&gt;, but constructed in a way that 'fills space' instead of substituting a segment with a copy of the whole structure. What this means is that we define basic components, so for the Hilbert curve we'll have a Clockwise Spin and an Anticlockwise Spin component:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/S2qiBHqjqoI/AAAAAAAAADc/JCe_O0o2XoY/s1600-h/HilbertOperators.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 164px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/S2qiBHqjqoI/AAAAAAAAADc/JCe_O0o2XoY/s400/HilbertOperators.png" alt="" id="BLOGGER_PHOTO_ID_5434334040497040002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;We also have logical rules for how each component is recursively composed of sub-components, so we have two different 1st-order Hilbert curves (ignoring effects of rotation):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/S2qiCT06knI/AAAAAAAAADs/_NG1kVLbsm8/s1600-h/HilbertClockwiseOrder.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 200px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/S2qiCT06knI/AAAAAAAAADs/_NG1kVLbsm8/s400/HilbertClockwiseOrder.png" alt="" id="BLOGGER_PHOTO_ID_5434334060941578866" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qiCLvGYHI/AAAAAAAAADk/e6lqojVtJKI/s1600-h/HilbertAntiClockwiseOrder.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 200px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qiCLvGYHI/AAAAAAAAADk/e6lqojVtJKI/s400/HilbertAntiClockwiseOrder.png" alt="" id="BLOGGER_PHOTO_ID_5434334058769703026" border="0" /&gt;&lt;/a&gt;As you can see, a component would occupy one cell, i.e. one dot in the artwork representing one bit. Going to the next level (2nd-order, etc.) means that this cell is divided into four. Following the path according to the direction rotation means that the sub-components are defined in the order 1-0-0-1 (where 1 indicates the sub-component is different to the parent component type). Once a sub-component has been 'rendered', the next component to render is determined by the type of parent component.&lt;br /&gt;&lt;br /&gt;For an 8x8 grid, we only need to do this to the 3rd-order, yielding the curve below. This starts with an Anticlockwise spin as the 1st-order curve, starting in the top-left corner. The three most-significant bits for each character form a different pattern, though it isn't so bold as the straight grid before.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PtRfH0rESBo/S2qiCvT77JI/AAAAAAAAAD0/5UBLgBzPZYY/s1600-h/HilbertScramble.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 358px; height: 358px;" src="http://2.bp.blogspot.com/_PtRfH0rESBo/S2qiCvT77JI/AAAAAAAAAD0/5UBLgBzPZYY/s400/HilbertScramble.png" alt="" id="BLOGGER_PHOTO_ID_5434334068319448210" border="0" /&gt;&lt;/a&gt;So all that's left is to follow the path and fill in the remaining bits, to achieve the final result:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qjPPwSqHI/AAAAAAAAAD8/Q8bVmr2c3RU/s1600-h/HilbertFinal.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 372px; height: 368px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/S2qjPPwSqHI/AAAAAAAAAD8/Q8bVmr2c3RU/s400/HilbertFinal.png" alt="" id="BLOGGER_PHOTO_ID_5434335382698371186" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3890255917985677743?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3890255917985677743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3890255917985677743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3890255917985677743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3890255917985677743'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2010/02/visual-art-meets-maths-computer-science.html' title='Visual Art Meets Maths / Computer Science'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PtRfH0rESBo/S2qiAwrv8DI/AAAAAAAAADU/LAM_82PRQSY/s72-c/BinaryArtOriginal.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3252308069145753706</id><published>2010-02-03T21:44:00.003+13:00</published><updated>2010-02-03T22:41:52.781+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>Now Certified in WPF (plus a binding tip)</title><content type='html'>As the title says, I'm now certified with an MCTS in Windows Presentation Foundation applications, having passed the &lt;a href="http://www.microsoft.com/learning/en/us/exam.aspx?ID=70-502&amp;amp;locale=en-us"&gt;70-502&lt;/a&gt; exam. (I've heard it's a tough one.) There were 50 multiple-choice questions to answer in something like 2:30 hours. As would be expected, the toughest questions were the ones I didn't really have experience in, like aspects of ClickOnce deployment, though these were balanced out by the XAML-related questions.&lt;br /&gt;&lt;br /&gt;So anyway, after my moment of euphoria I was working on performing a custom data migration into &lt;a href="http://crm.dynamics.com/"&gt;Dynamics CRM 4&lt;/a&gt;, since the Bulk Data Import was inadequate for our mapping needs. I had previously bult a small WPF utility to start a bulk delete of records (for remigrating data), so was in the process of extending it to perform this custom migration.&lt;br /&gt;&lt;br /&gt;In this mode, the user selects a CSV file from the file system prior to performing the migration. This is done by clicking a 'browse' button, which displays an &lt;a href="http://msdn.microsoft.com/en-us/library/aa969773.aspx#Open_File_Dialog"&gt;OpenFileDialog&lt;/a&gt; for the user to select the file. Once the file is 'opened', the adjacent TextBox is updated with the selected path and file name. What makes this interesting is that the application uses the &lt;a href="http://en.wikipedia.org/wiki/Model_View_ViewModel"&gt;MVVM&lt;/a&gt; (Model-View-ViewModel) pattern.&lt;br /&gt;&lt;br /&gt;Since it uses the MVVM pattern, the TextBox is bound to the ViewModel in a two-way mode. This means that when the TextBox's Text property is being set programmatically, it uses the code:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;csvPath.SetValue(TextBox.TextProperty, selectedFilePath);&lt;/span&gt;&lt;/blockquote&gt;rather than:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;csvPath.Text = selectedFilePath;&lt;/span&gt;&lt;/blockquote&gt;At first, this seemed to work - the TextBox was being updated to show the new value. However when the migration was being performed, stepping through the code revealed that the ViewModel contained the old (default) value.&lt;br /&gt;&lt;br /&gt;The solution?&lt;br /&gt;&lt;br /&gt;All bindings have an &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx"&gt;UpdateSourceTrigger&lt;/a&gt; property, which determines when the binding source gets updated. Nearly all controls have a default value of &lt;span style="font-weight: bold;"&gt;PropertyChanged&lt;/span&gt;, so that the source is updated as soon as the property value changes.  TextBoxes tend to buck the trend and by default, update the source when the TextBox loses focus. Since the property is being set in code, the TextBox never gets focus in order to lose it so that the ViewModel gets updated.&lt;br /&gt;&lt;br /&gt;Therefore, the TextBox and its binding should be defined in XAML as follows:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;TextBox x:Name="csvPath"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text="{Binding Path=CsvPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /&amp;gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3252308069145753706?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3252308069145753706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3252308069145753706' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3252308069145753706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3252308069145753706'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2010/02/now-certified-in-wpf-plus-binding-tip.html' title='Now Certified in WPF (plus a binding tip)'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-21403449131604069</id><published>2010-01-23T15:40:00.006+13:00</published><updated>2010-01-23T17:25:32.589+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EPiServer'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>A New Website - Featuring EPiServer Composer</title><content type='html'>This week had quite a noteworthy event - the Go-Live of Intergen's new &lt;a href="http://www.intergen.co.nz/"&gt;public website&lt;/a&gt;, which I was significantly involved with in terms of development. What made this particularly unique was that it was our first project using &lt;a href="http://www.episerver.com/en/Products/EPiServer-Composer/"&gt;EPiServer Composer&lt;/a&gt; - a fairly new extension to the core content management system (CMS). This allows reusable components to be included in pages at the whim of content editors, which allows fewer page templates to be defined. So how does this compare with previous sites build using just the standard EPiServer CMS?&lt;br /&gt;&lt;br /&gt;In the past, when developing such websites, our development team would determine the page templates that had to be built in order to deliver the functionality of each page in the site, as well as support different visuals for different sections of the site. This means that pages with similar layout (but different content) could use the same template (referred to as Page Types in EPiServer terminology). If the client required one of these pages to have an additional column or section, this would usually require a separate template to be built. As a result, it would be possible that many templates would be required, some with close similarities to each other.&lt;br /&gt;&lt;br /&gt;With the reusable components created for a site using EPiServer Composer, the page templates can be simplified and made more generic. As an example, many sites have a media gallery feature. Traditionally, the gallery would be one template, each image item would be another. If the gallery also supported videos, each video item would need to use a third template.&lt;br /&gt;&lt;br /&gt;In Composer, the gallery itself could be a component - which allows it to be placed inside a content block on&lt;span style="font-style: italic;"&gt; any&lt;/span&gt; compatible page, whether a standard content page or section summary/landing page. This is exactly what has happened with the Intergen site, where an image gallery can be found on a &lt;a href="http://www.intergen.co.nz/Who-We-Are/Recognition-and-Awards/"&gt;standard content page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Obviously, there are a few new things to learn when developing with EPiServer Composer. A reasonably good crash-course can be found &lt;a href="http://world.episerver.com/Articles/Items/EPiServer-Composer---Best-Practices-for-Developers/"&gt;here&lt;/a&gt; (if you're already used to the main aspects of working with standard EPiServer CMS). Here are a few things I also found out through experience on this project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Composer elements (content functions and layout functions) are technically defined as EPiServer pages themselves, which are stored in a page hierarchy below a page called something like '[Extension page container]'. All Composer elements in the entire site are stored under that single hierarchy.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;This single page tree is separate from the content pages that use the Composer elements. For global elements, this makes sense; for page-specific elements, they would be better suited to below the page itself. This is something to watch out for when migrating pages via export and import - the Composer structure needs to be migrated with the content.&lt;/li&gt;&lt;li&gt;Because Composer elements could be potentially used on any page (despite setting composition rules), it is a good idea to keep the CSS classes defined according to the specific component, rather than rely on classes associated with page type. If components are styled differently for different sections of the site, such styles can override the default, but a style should always be defined so that it doesn't appear broken on particular pages.&lt;/li&gt;&lt;li&gt;For different components that are effectively complex web controls, ensure the CSS class names do not collide, e.g. having general ".item" classes without a parent to distinguish between control, e.g. ".tabbedView .mapView .item".&lt;/li&gt;&lt;li&gt;Since multiple components can potentially be used on the same page, avoid using (and relying on) HTML element IDs. There should be no CSS style with a '#' (unless it is specifically part of the page's chrome and can only appear once on any page).&lt;/li&gt;&lt;li&gt;Because of the use of CSS classes for dynamic components, the &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; JavaScript library becomes very useful - especially from its ability to select elements in the same manner as CSS. No need to rely on HTML element IDs.&lt;/li&gt;&lt;li&gt;If multiple dynamic components of the same type exist on a page, writing custom jQuery plugins is very useful in separating each component's behaviour so that it doesn't affect the other components.&lt;/li&gt;&lt;/ul&gt;Meanwhile, feel free to explore the &lt;a href="http://www.intergen.co.nz/Blog/"&gt;Intergen Blog&lt;/a&gt; for &lt;a href="http://www.intergen.co.nz/Blog-Search/?tag=website%2bredevelopment"&gt;other perspectives&lt;/a&gt; on this project. Enjoy the new site!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-21403449131604069?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/21403449131604069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=21403449131604069' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/21403449131604069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/21403449131604069'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2010/01/new-website-featuring-episerver.html' title='A New Website - Featuring EPiServer Composer'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-1888986586965972106</id><published>2009-08-08T13:39:00.008+12:00</published><updated>2009-08-08T15:18:45.025+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Usability'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>Multilingual WPF Applications - on CodeProject</title><content type='html'>Well it seems that multilingual WPF applications is a hot topic, at least according to my most visited posts and a few questions posted on CodeProject. That has kick-started me into writing an article based on my implementation described here (in what became parts &lt;a href="http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html"&gt;1&lt;/a&gt;, &lt;a href="http://tech-and-arts.blogspot.com/2009/07/multilingual-wpf-applications-part-2.html"&gt;2&lt;/a&gt; and &lt;a href="http://tech-and-arts.blogspot.com/2009/07/building-multilingual-wpf-applications.html"&gt;3&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The article may be viewed at:&lt;br /&gt;&lt;a href="http://www.codeproject.com/KB/WPF/Multilingual-WPF-Apps.aspx"&gt;http://www.codeproject.com/KB/WPF/Multilingual-WPF-Apps.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/Snzcmi6OgzI/AAAAAAAAADM/9IWpgQfNAXo/s1600-h/LanguageList.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 360px; height: 390px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/Snzcmi6OgzI/AAAAAAAAADM/9IWpgQfNAXo/s400/LanguageList.png" alt="" id="BLOGGER_PHOTO_ID_5367407410682954546" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Being my first CodeProject article, it was a bit of a learning experience. Fortunately there's some good information on getting started with &lt;a href="http://www.codeproject.com/info/submit.aspx"&gt;writing &amp;amp; submitting articles&lt;/a&gt; and perspectives on how to make it a &lt;a href="http://www.codeproject.com/KB/mentor/whatisagoodarticle.aspx"&gt;good article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The good thing that an &lt;a href="http://www.codeproject.com/info/codeproject_template.zip"&gt;article template&lt;/a&gt;&lt;a href="http://www.codeproject.com/info/codeproject_template.zip"&gt; [ZIP]&lt;/a&gt; is provided with HTML file for writing the article, which is a good way to work on it offline and preview how it will look when it's published.&lt;br /&gt;&lt;br /&gt;When it comes to submission and publishing, I chose to use the submission wizard rather than email it by ZIP file. While this has its convenient advantages, there are a few points to note:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can't simply upload the ZIP file containing the article (in HTML), code sample (in nested ZIP) and images in one step. Instead, you need to upload each image and ZIP file (containing code) separately on one page, then input the article on the next page of the wizard.&lt;/li&gt;&lt;li&gt;The article itself is input using the WYSIWYG editor that supports rich formatting. Fortunately, this contains an HTML mode, so you can simply copy the article body from your HTML file and paste in the HTML view. You don't need to copy the &amp;lt;pre&amp;gt; tag containing the information you fill out online earlier in the submission wizard.&lt;/li&gt;&lt;li&gt;If you have images, you'll need to change the URL to be relative to your article (as the instructions indicate on the wizard page). This is largely dependent on what you choose as your base name as displayed in the browser's address bar.&lt;/li&gt;&lt;li&gt;Code fragments in &amp;lt;pre&amp;gt; tags need to have the 'lang' attribute assigned if using any language apart from C++. You won't see the difference when editing the article offline, but when it comes to previewing it online, this will make the difference for what syntax colouring you get. Doing this earlier saves time when you go through the submission process.&lt;/li&gt;&lt;/ul&gt;Other things I learned in the process:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;When quoting internationalised text, watch the encoding of the HTML file. I changed this to UTF-8 so that foreign scripts like Japanese ひらがな (Hiragana) didn't show up as blocks or question marks.&lt;/li&gt;&lt;li&gt;Take care of how the HTML comments are handled. In the text editor (&lt;a href="http://notepad-plus.sourceforge.net/"&gt;Notepad++&lt;/a&gt;), everything was fine. When it came to viewing it in Firefox, most of the article ended up being commented out. Fortunately I discovered a hack - simply add "&amp;lt;!--&amp;gt;&amp;lt;--&amp;gt;" (without quotes) before your article content. I've no idea what was causing this!&lt;/li&gt;&lt;li&gt;While it takes a bit of time writing the article, don't underestimate how long it takes to provide a code sample, even if it can be extracted from a different project. It takes a long time to tidy things up so that redundant parts are removed, and to ensure that the sample is of good quality (as much as the article). There is a tricky balance - to ensure the code is easy to follow and credible, while getting it done as quickly as possible.&lt;/li&gt;&lt;/ul&gt;And lastly, it's a good thing to have fun in the process - it probably shows, given that I styled the sample.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-1888986586965972106?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/1888986586965972106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=1888986586965972106' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1888986586965972106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1888986586965972106'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/08/multilingual-wpf-applications-on.html' title='Multilingual WPF Applications - on CodeProject'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PtRfH0rESBo/Snzcmi6OgzI/AAAAAAAAADM/9IWpgQfNAXo/s72-c/LanguageList.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-590007580502060103</id><published>2009-07-19T20:39:00.008+12:00</published><updated>2009-07-19T22:53:49.916+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>Building Multilingual WPF applications - Part 3</title><content type='html'>Since &lt;a href="http://tech-and-arts.blogspot.com/2009/07/multilingual-wpf-applications-part-2.html"&gt;Part 2 on building Multilingual WPF applications&lt;/a&gt;, one unresolved issue has grabbed my attention as the proverbial stone in one's shoe - that of not getting the custom markup extension working correctly. As a refresher, I had &lt;a href="http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html"&gt;implemented a strategy&lt;/a&gt; to change the interface language at run-time without needing to compile satellite assemblies (and have multiple versions of the same application, one for each language). I also noticed how the bindings from the UI to (what is now) the ViewModel were quite long and ugly when reproducing the same lines of XAML for each element that needed localised text, and sought to replace these expressions with something simpler.&lt;br /&gt;&lt;br /&gt;So at the end of Part 2, I had managed to simplify ridiculously long binding expressions such as this:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock Text="{Binding Path=currentLanguage,&lt;br /&gt;Converter={StaticResource uiText}, ConverterParameter=ApplyAllLabel,&lt;br /&gt;Source={x:Static vm:CommonViewModel.current}}" /&amp;gt;&lt;/blockquote&gt;to this, via attached properties:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock vm:Extensions.TextKey="ApplyAllLabel" /&amp;gt;&lt;/blockquote&gt;However, there was a major flaw - it created a dependency on there being a Text property on the control, which basically had to be a TextBlock. For custom label controls, this logic (and the attached dependency properties) had to be replicated. An ugly hack that shouldn't need to be done.&lt;br /&gt;&lt;br /&gt;So I had another crack at implementing this via a custom markup extension, remembering that a Binding is a MarkupExtension, like the custom extension I was creating. That means that the ProvideValue method simply has to invoke the ProvideValue method on the underlying Binding, and return the result. Therefore, my custom markup extension needed the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A private Binding instance, which is initialised in the constructor,&lt;/li&gt;&lt;li&gt;A public property, which gets and sets the CommandParameter of the Binding (i.e. the text key)&lt;/li&gt;&lt;li&gt;The ProvideValue implementation, as mentioned above:&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote style="font-family: courier new;"&gt;public override object ProvideValue(IServiceProvider serviceProvider)&lt;br /&gt;{&lt;br /&gt;     return _lookupBinding.ProvideValue(serviceProvider);&lt;br /&gt;}&lt;/blockquote&gt;To use it in the UI, the markup extension is used in the following way:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock Text="{ext:LocalisedText Key=ApplyAllLabel}" /&amp;gt;&lt;/blockquote&gt;Even better, the same markup extension can be used for custom controls, such as my labelled form controls:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;uiCt:TextLabel labelText="{ext:LocalisedText Key=DescriptionLabel}" /&amp;gt;&lt;/blockquote&gt;The good news is the output is the same:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PtRfH0rESBo/SmL42gnSmaI/AAAAAAAAACs/zmDjEVXkt14/s1600-h/MultiLingual3-EN.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 302px;" src="http://1.bp.blogspot.com/_PtRfH0rESBo/SmL42gnSmaI/AAAAAAAAACs/zmDjEVXkt14/s400/MultiLingual3-EN.png" alt="" id="BLOGGER_PHOTO_ID_5360120121875667362" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/SmL422ivLRI/AAAAAAAAAC0/mhKZzLZm_0Y/s1600-h/MultiLingual3-DE.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 302px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/SmL422ivLRI/AAAAAAAAAC0/mhKZzLZm_0Y/s400/MultiLingual3-DE.png" alt="" id="BLOGGER_PHOTO_ID_5360120127762148626" border="0" /&gt;&lt;/a&gt;&lt;h4&gt;Localising Right-to-Left Languages&lt;/h4&gt;One other thing that was left unresolved from &lt;a href="http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html"&gt;Part 1&lt;/a&gt; was the notion of localising right-to-left languages. The problem is best described by the following screenshot:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/SmL43AnT8JI/AAAAAAAAAC8/IFPQWvmQ1Gc/s1600-h/MultiLingual3-AR-nonRTL.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 302px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/SmL43AnT8JI/AAAAAAAAAC8/IFPQWvmQ1Gc/s400/MultiLingual3-AR-nonRTL.png" alt="" id="BLOGGER_PHOTO_ID_5360120130465689746" border="0" /&gt;&lt;/a&gt;For readers of right-to-left languages such as Hebrew and Arabic, the UI would be somewhat confusing when its layout doesn't flow logically in a manner consistent with reading order.&lt;br /&gt;&lt;br /&gt;So I embarked on an adventure to perform this extra localisation, armed with the buzz from getting the custom markup extension working. This saw me creating converters for Thicknesses (for Margin and Padding), CornerRadiuses (for Borders), Dock property enumerations, and HorizontalAlignment. Piece by piece, I was getting the interface flipped in the right order. I was just creating the conversions for the Grid's ColumnDefinitions property and Column attached property, when I discovered something that made all this unnecessary.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.flowdirection.aspx"&gt;FrameworkElement.FlowDirection&lt;/a&gt; (attached) property.&lt;br /&gt;&lt;br /&gt;The beauty of this is that I only need one binding - at the root level control inside the main window - since this value is inherited by every FrameworkElement below it in the visual hierarchy. This binding only needs to look at the 'isRightToLeft' property of the UILanguageDefinition instance and convert that (via a ValueConverter) to a FlowDirection enumeration, and a custom markup extension is created to simplify the 'binding' expression in XAML.&lt;br /&gt;&lt;br /&gt;Naturally, this attached property is quite powerful. Here are some points / gotchas to consider:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Custom panels are automatically laid out in reverse, so you do not need to create an 'isReversed' property (or similar) and adjust your ArrangeOverride calculations accordingly.&lt;/li&gt;&lt;li&gt;Bitmap images and shapes (e.g. Paths) are reversed. If you want to preserve the rendering of these, independent of flow direction (e.g. for corporate logos / branding), then you need to override the FlowDirection by setting it to LeftToRight.&lt;/li&gt;&lt;li&gt;If the interface has a FlowDirection of RightToLeft and an element (e.g. Image) has a FlowDirection of LeftToRight, then the Margin on the element will act in a RightToLeft manner. Since a Padding acts on the internal visual hierarchy of the element, a padding will behave in a LeftToRight manner.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;TextBoxes containing language-invariant data should have the FlowDirection set to LeftToRight. Ideally, this should be set in a Style to minimise repetition and guarantee consistency.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So in practice, the main window's immediate child element, a DockPanel, is declared as:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;DockPanel FlowDirection="{ext:LocalisedFlowDirection}"&amp;gt;&lt;/blockquote&gt;where the LocalisedFlowDirectionExtension is defined as follows:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;public class LocalisedFlowDirectionExtension : MarkupExtension&lt;br /&gt;{&lt;br /&gt;    private Binding _flowDirectionBinding;&lt;br /&gt;&lt;br /&gt;    public LocalisedFlowDirectionExtension()&lt;br /&gt;    {&lt;br /&gt;        _flowDirectionBinding = FlowDirectionConverter.createBinding();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public override object ProvideValue(IServiceProvider serviceProvider)&lt;br /&gt;      {&lt;br /&gt;                  return _flowDirectionBinding.ProvideValue(serviceProvider);&lt;br /&gt;      }&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;The static createBinding method creates a binding that uses a shared converter with this logic at the core of its Convert method:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;bool isRightToLeft = (bool)value;&lt;br /&gt;return (isRightToLeft)? FlowDirection.RightToLeft : FlowDirection.LeftToRight;&lt;br /&gt;&lt;/blockquote&gt;With that done, the UI is rendered as expected:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/SmL43e2pHII/AAAAAAAAADE/sXAGB0zkhPg/s1600-h/MultiLingual3-AR.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 302px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/SmL43e2pHII/AAAAAAAAADE/sXAGB0zkhPg/s400/MultiLingual3-AR.png" alt="" id="BLOGGER_PHOTO_ID_5360120138583055490" border="0" /&gt;&lt;/a&gt;Onwards and upwards.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-590007580502060103?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/590007580502060103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=590007580502060103' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/590007580502060103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/590007580502060103'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/07/building-multilingual-wpf-applications.html' title='Building Multilingual WPF applications - Part 3'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PtRfH0rESBo/SmL42gnSmaI/AAAAAAAAACs/zmDjEVXkt14/s72-c/MultiLingual3-EN.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-698270034956996927</id><published>2009-07-14T21:22:00.005+12:00</published><updated>2009-07-15T00:02:33.360+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Backstage Behind the Scenes</title><content type='html'>Today marks the launch of Office 2010's technical preview, accompanied by a new site showcasing the work that Microsoft has been putting in to deliver Office 2010 - &lt;a href="http://www.office2010themovie.com/"&gt;http://www.office2010themovie.com/&lt;/a&gt;. As one of the developers working on the site, I am able to provide a brief behind-the-scenes of the Behind-the-Scenes, so to speak. Since I mostly worked on the Silverlight-based front-end, this will mainly focus on the Silverlight aspect of the site - although a pure HTML version exists for visitors using mobile phones.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PtRfH0rESBo/SlxRB6FMROI/AAAAAAAAACc/HeaCwhmjUKk/s1600-h/BackstageWithOffice2010.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 322px;" src="http://2.bp.blogspot.com/_PtRfH0rESBo/SlxRB6FMROI/AAAAAAAAACc/HeaCwhmjUKk/s400/BackstageWithOffice2010.png" alt="" id="BLOGGER_PHOTO_ID_5358246749876798690" border="0" /&gt;&lt;/a&gt;As you can probably guess, the entire page (i.e. not just the video player) is pure Silverlight 2.0. This has a number of benefits over using a mixture of HTML and Silverlight objects:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Navigation between various 'pages' (I prefer to refer to these as 'Views') does not affect the inter-page navigation as is stored in the browser's history. This makes it very useful for online applications where entities are added, viewed, edited and removed without the 'back' button history growing ever larger. No need to do asynchronous JavaScript either.&lt;/li&gt;&lt;li&gt;The layout possibilities are more flexible without resorting to table-based layouts in HTML. Even if layout is div-based and using CSS, there are a number of common technical limitations that make some aspects of design impractical for web pages, for example &lt;a href="http://www.positioniseverything.net/articles/onetruelayout/equalheight"&gt;equal column heights&lt;/a&gt; with variable content in each column. &lt;/li&gt;&lt;li&gt;Every control can be styled in a much more flexible manner by overriding control templates. That's how we were able to add shadow effects and gradients to the text boxes, for example.&lt;/li&gt;&lt;/ul&gt;While Silverlight 2 has its limitations in comparison with WPF (as &lt;a href="http://tech-and-arts.blogspot.com/2009/07/another-step-for-silverlight.html"&gt;previously mentioned&lt;/a&gt;), it still allows the creation of custom panels so that the desired layout mechanism can be achieved. In the absence of a suitable WrapPanel for preserving right-justification of the 'Play Video' button in the video catalogue list, I was able to create one from scratch. (See the below WPF screenshot for why the standard WrapPanel is inadequate.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PtRfH0rESBo/SlxpwyvtU4I/AAAAAAAAACk/Czd5BN1hVr0/s1600-h/WPFWrapPanelQuirk.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 196px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/SlxpwyvtU4I/AAAAAAAAACk/Czd5BN1hVr0/s400/WPFWrapPanelQuirk.png" alt="" id="BLOGGER_PHOTO_ID_5358273943640560514" border="0" /&gt;&lt;/a&gt;There are some cases where particular layouts may be possible in HTML+CSS with floating divs, etc., however there are many cases where ugly hacks and/or verbosity would be needed to come close to the intended design. (Stay tuned for another custom panel coming to the home view on July 20...)&lt;br /&gt;&lt;br /&gt;The project itself took our team (4 developers, 1 designer, a project manager, deployment engineer and client liaison representative/tester) a little over two weeks sprinting from start to finish, with the application being functionally-complete (or as close as possible to it) at the end of the first week. That left this past week for styling the interface from generic black rectangles to the polished interface you see on the live site - including stabilisation and design convergence (making the actual interface match the design mockups down to the nearest pixel, where possible).&lt;br /&gt;&lt;br /&gt;Naturally, there were challenges along the way. Challenges such as getting the player working correctly with streaming video, supporting mouse-wheel scrolling on as many browsers as possible, implementing the Model-View-ViewModel (MVVM) pattern without native Silverlight commands (Thanks, Chris, for introducing me to &lt;a href="http://chris.59north.com/post/Creating-a-command-manager-in-Silverlight-2.aspx"&gt;your implementation&lt;/a&gt;). Yes, there was the figurative blood, sweat and tears as we battled seemingly endless design tweaks, compile times and bugs. But it was worth it, and I, for one, enjoyed it.&lt;br /&gt;&lt;br /&gt;Now, time to celebrate...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-698270034956996927?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/698270034956996927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=698270034956996927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/698270034956996927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/698270034956996927'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/07/backstage-behind-scenes.html' title='Backstage Behind the Scenes'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PtRfH0rESBo/SlxRB6FMROI/AAAAAAAAACc/HeaCwhmjUKk/s72-c/BackstageWithOffice2010.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3071724791962625690</id><published>2009-07-10T21:20:00.005+12:00</published><updated>2009-07-10T22:31:22.323+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Another Step for Silverlight...</title><content type='html'>Hooray - &lt;a href="http://silverlight.net/GetStarted/"&gt;Silverlight 3.0&lt;/a&gt; has just been released today, bringing it another step forward (and a little bit closer to WPF - at least in .NET 3.5). I have had the fortune of working on a few Silverlight-based projects at work, mostly using Silverlight 2. While that has come a long way from Silverlight 1.0 (and 1.1 alpha), it had its quirks that had me yearning for WPF.&lt;br /&gt;&lt;br /&gt;Quirks like no DockPanel, WrapPanel or ViewBox. No triggers either - a VisualStateManager instead. No element-to-element data binding. A RenderTransform on UIElements, but no LayoutTransform as well (see the difference in the WPF screenshot below).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PtRfH0rESBo/SlcUhno9o_I/AAAAAAAAACU/l_fYUXUumXk/s1600-h/LayoutAndRenderTransform.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 292px; height: 213px;" src="http://1.bp.blogspot.com/_PtRfH0rESBo/SlcUhno9o_I/AAAAAAAAACU/l_fYUXUumXk/s400/LayoutAndRenderTransform.png" alt="" id="BLOGGER_PHOTO_ID_5356772849589527538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;On my current project, I have been involved with skinning the application to match the visual design produced by one of our internal designers. This included restyling the scrollbars in the ScrollViewer for a cleaner look, which made me somewhat uneasy as I had done this as part of implementing &lt;a href="http://www.buttercupreader.net/"&gt;ButtercupReader&lt;/a&gt; with mixed success. The good news was that the scrollbars matched the design and worked, though there was a small issue that had me stumped, with no hint at the time on the wider Internet. This issue reveals itself when scrolling to the very bottom (or right), and results in clipping off the end of the scrollbar as shown:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/SlcUPRSNCmI/AAAAAAAAACM/GPimibe2pkc/s1600-h/SLScrollbars-BCReader.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 157px; height: 162px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/SlcUPRSNCmI/AAAAAAAAACM/GPimibe2pkc/s400/SLScrollbars-BCReader.png" alt="" id="BLOGGER_PHOTO_ID_5356772534350842466" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Sure enough, this issue came up again on my current project - though a second pair of eyes had a crack at getting past the issue, and luckily was able to solve it.&lt;br /&gt;&lt;br /&gt;So what was the problem?&lt;br /&gt;&lt;br /&gt;The track was implemented as a Border spanning the appropriate rows (or columns) of the Grid that is at the heart of the scrollbar. For some reason, this caused some sort of internal mayhem that resulted in the clipping of the end of the scrollbars.&lt;br /&gt;&lt;br /&gt;The solution? Don't use a Border - use a Rectangle instead.&lt;br /&gt;&lt;br /&gt;Will this also be the case in Silverlight 3? Probably, given that this behaves the same with the latest Silverlight 3 runtime installed. However, things may be different if the application is built natively with Silverlight 3. Something to try out...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3071724791962625690?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3071724791962625690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3071724791962625690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3071724791962625690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3071724791962625690'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/07/another-step-for-silverlight.html' title='Another Step for Silverlight...'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PtRfH0rESBo/SlcUhno9o_I/AAAAAAAAACU/l_fYUXUumXk/s72-c/LayoutAndRenderTransform.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-1278124262089487531</id><published>2009-07-05T16:18:00.004+12:00</published><updated>2009-07-05T23:17:56.270+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>Multilingual WPF Applications: Part 2</title><content type='html'>In a &lt;a href="http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html"&gt;previous post&lt;/a&gt;, I set up a way to bind a WPF interface to a class containing localised strings, so that the language of the entire application can be dynamically switched at runtime. This is unlike the standard .NET way of creating satellite assemblies, which gives you a separate version of your application for each different language / locale supported.&lt;br /&gt;&lt;br /&gt;So far, this has been working nicely as I've been building up my WPF application, but one thing is becoming clear - it is tedious work repeating the same binding for every new TextBlock containing UI text (e.g. for labels and messages):&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;br /&gt;&amp;lt;TextBlock Text="{Binding Path=currentLanguage,&lt;br /&gt;        Converter={StaticResource uiText}, ConverterParameter=ApplyAllLabel,&lt;br /&gt;        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type uiCt:MainWindow}}}" /&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;There are two problems I see with this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's long. Too long - especially how often these bindings are used throughout the entire application.&lt;/li&gt;&lt;li&gt;The RelativeSource property setting is inefficient and fragile - traversing the hierarchy of visuals to find the parent window to retrieve the 'currentLanguage' property.&lt;/li&gt;&lt;/ul&gt;Firstly, avoiding the FindAncestor traversal. XAML has a nifty markup extension to reference a shared object, aptly named x:Static. This is perfect for the currentLanguage property as it is shared throughout the entire user interface. Using this also means that MainWindow is not the appropriate place to store such shared data.&lt;br /&gt;&lt;br /&gt;Hence, the introduction of a &lt;a href="http://blogs.msdn.com/johngossman/archive/2005/10/08/478683.aspx"&gt;ViewModel&lt;/a&gt; - in simple terms a 'Model' specific to the View.&lt;br /&gt;&lt;br /&gt;The ViewModel I constructed for storing the language data that every part of the UI binds to uses the Singleton design pattern and implements the &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx"&gt;INotifyPropertyChanged&lt;/a&gt; interface. This part is crucial for enabling the UI to automatically update the bindings when the source is changed. Given that the shared instance of this ViewModel is called 'current', the binding becomes:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock Text="{Binding Path=currentLanguage,&lt;br /&gt;        Converter={StaticResource uiText}, ConverterParameter=ApplyAllLabel,&lt;br /&gt;        Source={x:Static vm:CommonViewModel.current}}" /&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;where the 'vm' XML namespace is mapped to the namespace of the ViewModel in the solution.&lt;br /&gt;&lt;br /&gt;Once the insides have been wired up to update the ViewModel, the application reassuringly runs the same as before, at least from a visual point of view.&lt;br /&gt;&lt;br /&gt;However, the binding expression is still too long. I ended up making two attempts at making the XAML more succinct. As a learning exercise, the first attempt involved creating a custom markup extension (with inspiration from &lt;a href="http://www.hardcodet.net/2009/04/wpf-tooltips-through-markup-extension"&gt;Philipp Sumi&lt;/a&gt;). To cut a long story short, attempting to return Binding objects to the Text property caused an invalid cast exception, since the Text property expects &lt;span style="font-style: italic;"&gt;only&lt;/span&gt; a string. I learned that the Binding markup extension does &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; return a Binding object, but an object of the type expected by the DependencyProperty. (Philipp also posted an example of &lt;a href="http://www.hardcodet.net/2008/04/wpf-custom-binding-class"&gt;creating a custom Binding markup extension&lt;/a&gt;, alas I wasn't quite able to adapt that to my needs with success.)&lt;br /&gt;&lt;br /&gt;In the end, what &lt;span style="font-style: italic;"&gt;did &lt;/span&gt;work was using a &lt;a href="http://msdn.microsoft.com/en-us/library/cc903943%28VS.95%29.aspx"&gt;custom attached property&lt;/a&gt;. This went into a static class called Extensions, and provided a callback handler for the PropertyChanged event. This handler method creates a Binding in code and assigns it to the Text property of the (cast) TextBlock.&lt;br /&gt;&lt;br /&gt;So the DependencyProperty is defined as:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;public static readonly DependencyProperty TextKeyProperty =&lt;br /&gt;               DependencyProperty.RegisterAttached("TextKey",&lt;br /&gt;               typeof(string), typeof(Extensions),&lt;br /&gt;               new FrameworkPropertyMetadata("",&lt;br /&gt;        FrameworkPropertyMetadataOptions.AffectsMeasure,&lt;br /&gt;       onTextKeyChanged));&lt;/blockquote&gt;and the callback effectively becomes:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;private static void onTextKeyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)&lt;br /&gt;{&lt;br /&gt;       TextBlock castControl = obj as TextBlock;&lt;br /&gt;       string key = e.NewValue as string;&lt;br /&gt;       Binding lookupBinding = UITextLookupConverter.createBinding(key);&lt;br /&gt;       castControl.SetBinding(TextBlock.TextProperty, lookupBinding);&lt;br /&gt;}&lt;/blockquote&gt;This is using the same value converter as before, except the static instance is defined in the UITextLookupConverter instead of XAML. The 'createBinding' method creates the Binding like so:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;Binding languageBinding = new Binding("languageDefn")&lt;br /&gt;{&lt;br /&gt;       Source = CommonViewState.current,&lt;br /&gt;    Converter = _sharedConverter,&lt;br /&gt;    ConverterParameter = key,&lt;br /&gt;};&lt;br /&gt;&lt;/blockquote&gt;Finally, with the appropriate XML namespaces mapped, the XAML becomes:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock vm:Extensions.TextKey="ApplyAllLabel" /&amp;gt;&lt;/blockquote&gt;Nice.&lt;br /&gt;&lt;br /&gt;However, there is one drawback where creating a custom Binding markup extension would be a better strategy. This method is only useful for the Text property of a TextBlock. For other controls (e.g. custom controls) that display text in different properties, additional extended attributes would be needed for each unique DependencyProperty (even if similar custom controls can inherit from a common abstract base class, or implement a common interface to retrieve the appropriate DependencyProperty). A single custom (binding) markup extension would be able to be used for any property of any control that expects a string.&lt;br /&gt;&lt;br /&gt;For now, this is progress.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-1278124262089487531?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/1278124262089487531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=1278124262089487531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1278124262089487531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1278124262089487531'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/07/multilingual-wpf-applications-part-2.html' title='Multilingual WPF Applications: Part 2'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3286786519119195542</id><published>2009-06-20T20:42:00.006+12:00</published><updated>2009-06-21T02:04:57.640+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Music'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='General'/><title type='text'>Sprint vs Marathon</title><content type='html'>This week I have had to make a tough decision - to pull out of submitting my latest composition for consideration for an upcoming music festival. It is not a decision I have taken lightly, given how much effort I have already put into it and how much I want to be able to do this. However there are too many holes in the music with a little over a week to go before the deadline, which means that it would take a miracle or many late nights (and possibly an all-nighter) to finish. And there's little guarantee that it would be to a standard I can be proud of.&lt;br /&gt;&lt;br /&gt;So how did I get myself into this?&lt;br /&gt;&lt;br /&gt;I am a member of &lt;a href="http://www.canz.net.nz/"&gt;CANZ&lt;/a&gt; - the Composer's Association of New Zealand, which I first heard about when submitting an earlier work for a competition involving the NZSO &lt;a href="http://www.nzso.co.nz/education/nzso_nyo"&gt;National Youth Orchestra&lt;/a&gt; for their 2008 season. Members receive a regular newsletter which contains details of upcoming competitions, commissions and calls for scores. Most of these tend to have deadlines within 1-3 months from when the newsletter is received, which in reality is quite short for those in my situation who aren't professional composers or musicians, and can only develop pieces at nights or in weekends.&lt;br /&gt;&lt;br /&gt;As I &lt;a href="http://tech-and-arts.blogspot.com/2009/06/accelerating-creative-process.html"&gt;previously mentioned&lt;/a&gt;, I composed a score for my team's short film for the &lt;a href="http://www.48hours.co.nz/"&gt;48 Hours&lt;/a&gt; film competition. When I did the math, it worked out that I composed a little over two minutes of music in one long day - and that doesn't count the mental development of the ideas on the Friday night once I had understood the genre, storyline and mood of the film. This was effectively a sprint, in that I had to be at full throttle getting the score developed with little respite. Much like the rest of the team doing filming, etc.&lt;br /&gt;&lt;br /&gt;So when I received the latest newsletter, one call for scores took my interest. The downside: a short deadline of less than two months away, and none of my past pieces or works in various stages of development (conceptual or otherwise) fit into the combination of length (up to 15 minutes - the longer, the better) or instrumentation (chamber ensemble or subsets of). Therefore a new piece it was to be.&lt;br /&gt;&lt;br /&gt;Here's where my naivete set in. (Well actually I subconsciously knew it, but underestimated it.)&lt;br /&gt;&lt;br /&gt;Spurred on by two minutes of music in one day, I reasoned that it was possible to do 14 minutes in seven days. Well, weekends, to stretch it out and be fair on myself, and allow time for fixes and improvements. Besides, I also had the odd weeknight I could do when I had the energy. This was, after all, a marathon - but it was possible. Each weekend I had to be able to say, "I've achieved another two minutes" at the end of it.&lt;br /&gt;&lt;br /&gt;But here's the lesson: &lt;span style="font-weight: bold;"&gt;A sprint does &lt;/span&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;not&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; scale to a marathon.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As much as I wanted to do another two minutes, I could only do about 40 seconds at a time, e.g. on a Saturday, then struggle to develop things further the next day. Ideas were short, it was hard translating them into reality and I was tired. So I had to rest, though with anxiety of the looming deadline - meaning that it was just as hard to develop the ideas. More rest was needed, so I'd do that and struggle to get back into the flow. A devil's advocate would call it procrastination.&lt;br /&gt;&lt;br /&gt;Yes, &lt;span style="font-weight: bold;"&gt;attempting to sprint for extended periods of time causes burnout&lt;/span&gt;. You cannot complete a marathon by sprinting all the way non-stop.&lt;br /&gt;&lt;br /&gt;The best way to last the distance is to reduce the pace to what is comfortable, while still achieving what needs to be done. Music will develop in it's own time - you cannot force it to go faster, despite how much you'd like to be able to.&lt;br /&gt;&lt;br /&gt;Incidentally, this lesson doesn't just apply to creating music, but anything that requires concentration and/or creativity - like software development. To be really productive you need to be in the right environment with enough energy and little stress sustained over time. Make small and steady achievements. Step back and celebrate these achivements, because they give the fresh energy and motivation to last the distance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3286786519119195542?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3286786519119195542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3286786519119195542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3286786519119195542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3286786519119195542'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/06/sprint-vs-marathon.html' title='Sprint vs Marathon'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-7523299085732392384</id><published>2009-06-06T21:39:00.008+12:00</published><updated>2009-06-07T11:17:12.166+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Music'/><title type='text'>Accelerating the Creative Process</title><content type='html'>Probably the trickiest thing about composing music is bridging the gaps between different sections or melodic themes in the piece. You start out with a few basic ideas and rough plan of how the music will sound, but once you get the basic ideas down (opening, introduction of main theme, secondary theme, recapitulation and the end), you find that it amounts to not even half the final work - and it is all in pieces. Yes, bridging the gaps is hard, especially when the music has to actually sound interesting (non-repetitive, yet coherent) and meet particular time constraints (in more ways than one).&lt;br /&gt;&lt;br /&gt;Like composing and scoring for a short film produced from start to finish within 48 hours.&lt;br /&gt;&lt;br /&gt;Yes, I took on one very interesting challenge when I joined a team called Cinesoma as part of the &lt;a href="http://www.48hours.co.nz/2009/"&gt;48-hour&lt;/a&gt; film competition, to provide the music to a film none of us knew about - until the Friday evening when it all started.&lt;br /&gt;&lt;br /&gt;So from that moment, we learned we had to produce a Romance (a genre that many dread), which had to include a rock as a prop, a character best described as an 'exaggerator' called Alex Puddle, and the line of dialogue, "It doesn't fit." And the finished work had to be handed in by 7pm on the Sunday night - 48 hours after it began.&lt;br /&gt;&lt;br /&gt;The Friday night consisted of the brainstorming, when the plot was developed along with a script / storyboard. It was then that the creative vision was comunicated to me, so that I knew where my music was to come in and of what nature it was to be. In hindsight, I count it as a blessing (from a timing point-of-view) that since our film was a sci-fi romance, the music could come in from the last scene, with a sci-fi-sounding drone provided for the background for the rest of the film beforehand.&lt;br /&gt;&lt;br /&gt;This last scene, in general terms, was intended to convey a sense of pathos until the scientist and 'Lilith' were reunited. From there it was tender, warm romance through the remainder of the scene and final credits. With that in mind, I was able to get some much-needed sleep at home before the day of solid composing ahead of me. This provided a great opportunity for me to toss around ideas in my head - a way to listen to a virtual performance so that the music can develop.&lt;br /&gt;&lt;br /&gt;This is a key point - probably most of my ideas come to me when I can step back from the mechanics of the work itself and do something else as a bit of a 'breather'. I find many of my musical ideas tend to develop while walking to work, for instance.&lt;br /&gt;&lt;br /&gt;As I mentioned, I declared the Saturday as Composition Day, while the Sunday was Production Day. The entire piece - melody and harmony - had to be finalised from start to finish before I could return home for sleep. Knowing this, I adopted a similar workflow as I did for my earlier piece, "Cathedral": Just get the melodic themes and harmony down using only the essential instruments, re-orchestrate for repetitions as necessary (to keep things fresh), and refine as necessary.&lt;br /&gt;&lt;br /&gt;Easier said than done.&lt;br /&gt;&lt;br /&gt;Remember how the toughest part is bridging the gap? After the second repetition of the romantic theme, something different had to fit between that and the recapitulation of the romantic theme to the conclusion. Finding the secondary theme was easy enough (no, I didn't try to model it on Greensleeves); it was connecting the reinforcement of that theme to the recapitulation. In a dramatic manner. (I prefer to make my music dramatic.) To put it shortly, it took three revisions to get the progression sounding coherent, which involved removing the 3/4 against 6/8 timing, and simplifying the harmony to fit more within the base scale of D-flat.&lt;br /&gt;&lt;br /&gt;Sunday, or 'Production Day' as I called it, involved turning the composition into music and making it sound good. Fortunately, composing in Sibelius means that note velocities are adjusted in the exported MIDI file to make the performance sound as naturally expressive as possible. The trouble is that this doesn't fully apply to instruments where the volume can be controlled during the course of a note - in other words, anything apart from piano or percussion.&lt;br /&gt;&lt;br /&gt;My solution was to record it myself, using my &lt;a href="http://www.ewi-evi.com/4000s.htm"&gt;EWI 4000-S&lt;/a&gt;. Think of it as an electronic clarinet that also functions as a MIDI controller. What I have found, when trying to transfer the nuances into MIDI data that the computer / Cubase interprets, is that aftertouch is ignored. (Aftertouch is a way to adjust the velocity/loudness of a note that is already playing.) Instead, to get this to work I had to keep note-on velocities constant and link the breath sensor to channel volume. This means that any staves / channels containing two instruments (e.g. Oboe I and Oboe II) have to be separated so that every instrument is on its own channel.&lt;br /&gt;&lt;br /&gt;Recording presented its challenges, thanks to being relatively new to playing woodwind. Obviously, I had little time to practice, so I admittedly had to take shortcuts. Recording parts of a track separately improved the odds of getting an error-free recording, rather than to strive for perfection from start to finish. For trickier passages the success criteria had to be relaxed somewhat, so the classic technique of correcting wrong notes after recording was employed. However the complicating factor was the breath control - that (and the timing) had to be perfect, since this was separate from the actual notes. No aftertouch, remember?&lt;br /&gt;&lt;br /&gt;Anyway, the music was included on the film's soundtrack and we made the 7pm deadline. I'm proud to have worked with a great team, and was happy to celebrate when our film was shown on the Big Screen in our heats. The finished product of the music can be listened to here:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-7d8e0f02ff193d31" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v18.nonxt7.googlevideo.com/videoplayback?id%3D7d8e0f02ff193d31%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330158603%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6AD42F04AA56EC2E6EC2F7E88D021C00E6AD9468.80C9A4421BCBE147F4A0706279C4986695106B7A%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D7d8e0f02ff193d31%26offsetms%3D5000%26itag%3Dw160%26sigh%3DQ9N_G5gdJs7o_jH5Z6DPA090zbc&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v18.nonxt7.googlevideo.com/videoplayback?id%3D7d8e0f02ff193d31%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330158603%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6AD42F04AA56EC2E6EC2F7E88D021C00E6AD9468.80C9A4421BCBE147F4A0706279C4986695106B7A%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D7d8e0f02ff193d31%26offsetms%3D5000%26itag%3Dw160%26sigh%3DQ9N_G5gdJs7o_jH5Z6DPA090zbc&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Some behind-the-scenes photos can be seen on fellow team member, Roger Wong's &lt;a href="http://roget-in-kiwi-land.blogspot.com/2009/05/48-hours.html"&gt;blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So this month I am in the process of composing a new piece to meet a tight deadline of June 30th, where selected works will be presented at a music festival. The down-side is that none of my existing pieces (whether complete or in development) are suitable, given the criteria of being up to 15 minutes long and for small chamber arrangements (as opposed to an orchestra). So it truly was a challenge coming up with a concept to inspire the music - considering that the target length is in the 10-15 minute range. Now that that is sorted, I'm back at the hard part of developing the themes for the stages of the work and filling in the gaps. The saving grace is that there are fewer instruments to write for, so I can use my experience on 48 Hours as a guide for timing.&lt;br /&gt;&lt;br /&gt;I have to say that it was also inspirational to attend Friday's &lt;a href="http://www.nzso.co.nz/"&gt;NZSO&lt;/a&gt; concert, featuring Berlioz's "Symphonie Fantastique" - which turned out to be the highlight of the evening (despite the irritating flurry of coughing around the auditorium in between movements). Lindberg's Clarinet Concerto was interesting from a more technical point of view, especially considering the radical techniques that its performer, Kari Kriikku, used to explore new frontiers of possibility.&lt;br /&gt;&lt;br /&gt;The first few movements of Symphonie Fantastique were very interesting to hear, given the contrasts to the stirring fourth movement (Marche au supplice) that I have heard before. Mental note: Must get the CD. The William Tell Overture was a natural crowd-pleaser to start the evening and induce some foot-tapping, though the pace of the final section made me glad I was not one of the violinists. Overall, the concert provided another opportunity for my ideas to develop, while providing a few hours of enjoyment.&lt;br /&gt;&lt;br /&gt;Anything to help fill in those gaps.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-7523299085732392384?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=7d8e0f02ff193d31&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/7523299085732392384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=7523299085732392384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7523299085732392384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7523299085732392384'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/06/accelerating-creative-process.html' title='Accelerating the Creative Process'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-727068183014603197</id><published>2009-02-09T20:49:00.006+13:00</published><updated>2009-02-10T02:28:52.770+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns and Practices'/><title type='text'>MVP in Action</title><content type='html'>Back in August-September 2007 the concept of the MVP (Model-View-Presenter) pattern had finally 'clicked' with me, since attending Ron Jacobs' session at TechEd 2007 (&lt;a href="http://tech-and-arts.blogspot.com/2007/09/reflections-on-tech-ed-2007-part-4.html"&gt;summary here&lt;/a&gt;) and reading related literature online. Since then I have had quite a bit more exposure to it, admittedly half of it being with my own personal projects. I have to say there is nothing better when learning about a pattern than to try it out and develop it from something that doesn't work well and is combersome to maintain, to something more logical, cohesive and easy to follow.&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 324px;" src="http://3.bp.blogspot.com/_PtRfH0rESBo/SZAi2sImUGI/AAAAAAAAABc/RzxnXa8utkg/s400/MVP-Agility.jpg" alt="" id="BLOGGER_PHOTO_ID_5300775084370579554" border="0" /&gt;Here's a recap of MVP and where it has evolved from, based on my understanding and experience:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;The Monolithic Mess.&lt;/span&gt; Everything is found inside one class, which is usually the code-behind of an ASPX page, form or window. Often, in such demo-grade code, such a class will contain database access code inside an event handler, such as a button click event. Internal state is also stored in this self-contained class, even though it has little relation to the UI itself.&lt;br /&gt;&lt;br /&gt;Problems start to show when common functionality is identified and inevitably refactored into a separate method, especially as the interface becomes more complex with each additional element. What happens is that multiple controls invoke the same logic from their function handlers.&lt;br /&gt;&lt;br /&gt;Where there's input, there's also output. As the result of some action, the UI will usually be updated in some way to provide some sort of feedback on the state of the system. Some of this would lend itself naturally to refactoring into common methods, while other parts of the UI would need subtle differences catered for. Because this is all within one class, everything becomes one jumbled mess that is hard to maintain.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Two-Tier (Model &amp;amp; View).&lt;/span&gt; Here, separation of concerns has been introduced, possibly because of additional forms/pages/windows/controls, which share a common state (Model) and call common helper functions. Another reason to use this pattern is to support a domain model, which would naturally reside separately from the UI (View) classes. This achieves a level of redundancy-avoidance through shared functionality, but there are still issues.&lt;br /&gt;&lt;br /&gt;The various parts of the UI have access to the unified state and its relevant parts, however most of the control logic is still kept in the UI. Granted, the UI is somewhat simplified with all state management being handled by the Model, but there are still the inter-dependencies between an input event and its corresponding output responses. This becomes more complicated when dependencies cross to other parts of the UI. We can do better.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Model-View-Presenter (MVP).&lt;/span&gt; This pulls the co-ordination of input to output out of the View and puts it into a separate intermediate layer - the Presenter. As a result, the application is structured around the three layers, with the following responsibilities:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;View:&lt;/span&gt; This is responsible for defining the user interface itself. Its main concerns are responding to events and translating them into commands, and displaying output - i.e. determining &lt;span style="font-style: italic;"&gt;how&lt;/span&gt; to display the data that is given to it.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Model:&lt;/span&gt; This is the authoritative source of all data / state in the application, and a set of operations that directly relate to this data. Whenever the internal representation of what the application is all about changes, these changes are registered in the Model. This state transcends all levels of the persistence stack - memory, disk storage, database storage and/or web services. It is especially the database access and web service access components of the model where an interface would be beneficial to abstract away implementation details, particularly when the database engine used could be one of many.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Presenter:&lt;/span&gt; This is responsible for co-ordinating interactions between the view and the model (and may involve the use of a &lt;a href="http://msdn.microsoft.com/en-us/library/8xs8549b.aspx"&gt;BackgroundWorker&lt;/a&gt;). An important distinction is that it is interaction-focussed - the View is &lt;span style="font-style: italic;"&gt;always&lt;/span&gt; involved, whether as a caller or callee. If some logic deals only with details of the Model, it belongs in the Model.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;How do these components fit together? Basically in a chain, as illustrated by the following example of one of my earlier projects (HexCell, a WPF-based implementation of Sudoku and a few variants):&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 83px;" src="http://1.bp.blogspot.com/_PtRfH0rESBo/SZAi2giEoGI/AAAAAAAAABk/2Ddl4bLIOxU/s400/MVP-HexCell.png" alt="" id="BLOGGER_PHOTO_ID_5300775081256198242" border="0" /&gt;As you can see, the Presenter is connected to the Model and the View, but the View and Model have no knowledge of each other (though there may be common entities that the View may need to know about). The Model is composed of two parts: HexCellEngine, the domain model and logic for generating, validating and solving puzzles; and HexCellLib, the in-memory state of the application itself. The application is simple enough to have one main Presenter and a single View (a hint of things to come).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Now that we've seen (at a high level) what MVP is and where it came from, let's tackle the questions of how it can be implemented.&lt;br /&gt;&lt;h4&gt;Getting The Ball Rolling&lt;/h4&gt;Think about what happens when the application starts - a Model has to be initialised, the View created with its UI controls, and the Presenter linking the two together. By the time the UI is displayed, it should reflect the initial state of the Model, so there's one partial ordering needed: Model before (displaying) View. The application startup sits outside this 'triad', though the UI technology used will usually determine how this will be defined (e.g. in App.xaml[.cs], or Program.cs).&lt;br /&gt;&lt;br /&gt;Here is the approach I took in HexCell (not the Officially Mandated way of doing it):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Application creates the main window (View), but &lt;span style="font-style: italic;"&gt;does not display it&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Application creates the main Presenter, passing the main View as a reference to an interface.&lt;/li&gt;&lt;li&gt;Main Presenter creates the Model in its constructor and holds a reference to it (since it is purely in-memory, so no interface abstraction necessary - unless you wish to test the Presenter in isolation with mock View and Model).&lt;/li&gt;&lt;li&gt;Main Presenter binds events / sets delegates as necessary for interaction between the View and Model.&lt;/li&gt;&lt;li&gt;Main Presener calls the View to display itself in its initial state.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;If the Model has components that would be abstracted behind an interface (e.g. database access), the first three steps would be as follows:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Application creates the main window (View), but &lt;span style="font-style: italic;"&gt;does not display it&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Application creates the relevant Model components.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Application creates the main Presenter, passing the main View and relevant Model components as references to their corresponding interfaces.&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;Handling Multiple MVP 'Triads'&lt;br /&gt;&lt;/h4&gt;As applications become more complex, the interface becomes composed of several components that have different areas of responsibility, therefore one Presenter and View is not enough to handle the diverse functionality. Hence, &lt;a href="http://www.atomicobject.com/files/PresenterFirstAgile2006.pdf"&gt;some literature&lt;/a&gt; talks of constructing MVP "triads". In my view, a way to make this practical is to think of these triads as similar in concept to mini-applications hosted within one large host application. Keep in mind that these triads do not necessarily map 1:1 to each composite control within a window, in a way that a button doesn't need its own MVP triad.&lt;br /&gt;&lt;br /&gt;Dealing with multiple triads makes things a little trickier, but here are some principles I followed when structuring the application:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Main View instantiates itself and constructs its child View components.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The Main View provides interface implementations to get its component View references, e.g. GetSettingsView().&lt;/li&gt;&lt;li&gt;The Main Presenter initialises only its own state in the Model. This in turn initialises the complete Model for the entire application.&lt;/li&gt;&lt;li&gt;The central state object contains references to the components' state objects, much like declaring a 'tree of knowledge'.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The Main Presenter creates its child presenters, passing in the corresponding component View references obtained by GetSettingsView(), etc.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;As before, the Main View does not get displayed until the Main Presenter tells it to do so.&lt;/li&gt;&lt;li&gt;If a View needs access to a Presenter (to query the Model), it can only knows about its own direct Presenter.&lt;/li&gt;&lt;li&gt;A component Presenter cannot interact directly with another View apart from its own.&lt;/li&gt;&lt;li&gt;A component Presenter cannot interact directly with another component state in the Model apart from its own (or the main state).&lt;/li&gt;&lt;li&gt;A component Presenter cannot interact directly with another Presenter except the Main Presenter (or an ancestor, if multiple hierarchical levels are defined).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If a change in state requires multiple component Views to be updated, this should be done by allowing the respective Presenters to subscribe to the appropriate event in the Model.&lt;/li&gt;&lt;li&gt;The Model never interacts with any Presenter - either a Presenter accesses the Model or an event is raised.&lt;/li&gt;&lt;/ul&gt;So far, these principles have guided the architecture of my after-hours project and seem to be working out. A good example of this in action is the &lt;a href="http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html"&gt;changing of the language&lt;/a&gt; of the entire application from within the Settings View. When the setting is applied, the Settings Presenter calls the Main Presenter, which changes the current interface language in the Model (and loads the corresponding UI text). This change causes an event to be raised, which allows another component to refresh its View with the updated language data (since this UI text is applied programmatically, instead of using WPF data binding).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-727068183014603197?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/727068183014603197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=727068183014603197' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/727068183014603197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/727068183014603197'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/02/mvp-in-action.html' title='MVP in Action'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PtRfH0rESBo/SZAi2sImUGI/AAAAAAAAABc/RzxnXa8utkg/s72-c/MVP-Agility.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-4609654330562412865</id><published>2009-02-04T21:31:00.004+13:00</published><updated>2009-02-04T22:15:15.222+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Music'/><category scheme='http://www.blogger.com/atom/ns#' term='Usability'/><title type='text'>The Cost of Open Source</title><content type='html'>As a bit of background, I have composed a number of musical pieces in recent years, two of which have been submitted to competitions where selected works were performed by an affiliated orchestra. Obviously when submitting works to an orchestra, the score and its presentation is what matters most - not a MIDI file (which is limited to 16 channels to divvy up among the instrument parts), or even an MP3 rendering of a MIDI file. Especially since it is very hard to get the nuances of the dynamics right, unless each part is recorded on some sort of MIDI hardware (but I digress).&lt;br /&gt;&lt;br /&gt;If anyone has been involved with composing for an ensemble, they would find that there is also a standard to adhere to and conventions to follow when writing the score. Instruments have to be in the correct logical order, tempi must appear above both the top line in the score and the First Violins, full instrument names should appear on the first page and abbreviations on subsequent pages, etc. It should be obvious that to do this properly, you need decent software to help achieve the end results. (Who'd have the time and patience to write it by hand?) As you'd probably guess from the title, this post is more about how the software used fits into the process, rather than the music itself or any competition.&lt;br /&gt;&lt;br /&gt;Ask anyone academically or professionally involved with music what software they use for scorewriting, and you'll usually get one of two responses. &lt;a href="http://www.sibelius.com/"&gt;Sibelius&lt;/a&gt; or &lt;a href="http://www.finalemusic.com/"&gt;Finale&lt;/a&gt;. Usually the former. The only down-side to these packages is that the functionality needed for the intricacies of some pieces (be they multiple time signatures throughout a piece, divisi on separate staves, tuplets, single- and double-line staves for percussion, etc.) does not come cheap, with the market leader selling for over $1,000NZ (unless you're eligible for an academic discount). Don't get me wrong - Sibelius (version 5 anyway) is a great package - but there is an obvious financial cost involved. Note that I'm not considering cheaper packages - in many cases they are typically marketed as 'virtual studio' software or sequencers - designed for the audio (or MIDI) output. Others simply lack the capabilities simply needed for the demands of the score and impose limits such as 16 staves in a score (to coincide with the number of available MIDI channels - one of which is always for percussion).&lt;br /&gt;&lt;br /&gt;But surely there must be cheaper or even free software out there that does what is needed? Especially given the commitment of some to developing Open-Source Software.&lt;br /&gt;&lt;br /&gt;In many cases, there is the economic principle, 'you get what you pay for', but there are some notable software packages that go against this, and are gaining traction in their respective communities. &lt;a href="http://www.blender.org/"&gt;Blender&lt;/a&gt; is becoming a popular competitor to other 3D modelling and animation software; many would have discovered &lt;a href="http://distrowatch.com/dwres.php?resource=major"&gt;Linux&lt;/a&gt; (e.g. &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt;) and its applications; and around half reading this are probably reading this inside &lt;a href="http://www.mozilla.com/firefox/"&gt;Firefox&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Naturally, it shouldn't come as too much of a surprise that there is open-source scorewriting software out there. &lt;a href="http://www.rosegardenmusic.com/"&gt;Rosegarden&lt;/a&gt; is pretty capable, but is designed more as a sequencer than a dedicated notation package - and is only available on Linux. The other option (that I know of) is &lt;a href="http://lilypond.org/"&gt;LilyPond&lt;/a&gt; - software dedicated to &lt;a href="http://lilypond.org/web/about/automated-engraving/"&gt;engraving music with aesthetics&lt;/a&gt; of the output being a top priority. Because of this focus, not much attention is paid to the user interface. In fact, there is no user interface - if you want a WYSIWYG (what you see is what you get) interface in the vein of Sibelius or Rosegarden, you're out of luck.&lt;br /&gt;&lt;br /&gt;So how does LilyPond work?&lt;br /&gt;&lt;br /&gt;Music is written in a text editor, in a markup language (similar in concept to LaTeX for documents) devised by the people behind LilyPond, and saved as a LilyPond file (*.ly). LilyPond is run as a command-line process with the LilyPond file as a parameter. In Windows, there is a shortcut in the right-click menu (of Windows Explorer) for LilyPond files, which allows you to run LilyPond on the selected file. In either case, the engraved music is generated music in PostScript and PDF format. If there are errors in the input, these will be listed in a log file that is also generated. It is also possible to generate MIDI files from LilyPond input, so you can hear what the piece sounds like. Think of this as Computer Programming Meets Music.&lt;br /&gt;&lt;br /&gt;Unfortunately, when composing for a competition (or a commission), there is a deadline imposed. A limit on how much a piece can be crafted to perfection. I simply don't have time to work on a piece, learn the syntax of the &lt;a href="http://lilypond.org/doc/v2.12/Documentation/user/lilypond/index"&gt;LilyPond markup language&lt;/a&gt;, rewrite the piece in a text editor, and enter into the loop of producing output and debugging. I'm sure many other composers would feel the same - even if they have a similar programming / Computer Science background.&lt;br /&gt;&lt;br /&gt;Fortunately, there are tools to help improve efficiency. How many composers would really compose in a text editor and wait for LilyPond to do its thing before being able to preview what it sounds like in a MIDI file? Especially when there are potentially many cycles to get that phrase right? For me (and no doubt many others), I'd prefer to work in a WYSIWYG environment, where I can preview my changes immediately. The good thing is that Rosegarden provides such an environment, and is able to export music to LilyPond format. However, last time I tried this I had to correct parts of the output, since the LilyPond version was different to what was expected by LilyPond. It wasn't just changing the version number at the top - there were numerous markup extensions that were new, and others that became obsolete. So that was one all-nighter finishing off "Perpetual Restlessness" before submission. (Oh, the irony.)&lt;br /&gt;&lt;br /&gt;Lilypond also provides utilities to convert MIDI and MusicXML files into LilyPond format. Since I have experience with the MIDI to LilyPond converter, I'll walk through that using my more recent piece "Maui" as an example. In the knowledge that the true cost of using the free LilyPond was time (and the learning curve), I allocated much more time for getting the LilyPond output right. Here's the process I used to produce the score for "Maui" (first revision):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Compose the piece in Notation Package 'A'. This is the package that limits the score to 16 staves, meaning that I had to add both harp parts later. With this show-stopper, it was moot that notes didn't line up properly between staves or even voices (also a show-stopper - I don't have time to drag all the notes to where they should be).&lt;/li&gt;&lt;li&gt;Export to MIDI file #1.&lt;/li&gt;&lt;li&gt;Import MIDI file into Sequencer 'B' and add the harp parts. This sequencer lacked a score editor, so I had to create the notes in the piano roll view. Not the best interface for composing, unless you're working on a 12-tone piece and need to visualise the relationships.&lt;/li&gt;&lt;li&gt;Export to MIDI file #2.&lt;/li&gt;&lt;li&gt;Run 'midi2ly' on the second MIDI file to convert it to LilyPond format.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Here's the sort of output that was produced when LilyPond itself was run on the generated Maui.ly file:&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PtRfH0rESBo/SYlZgsf3S3I/AAAAAAAAABM/56Ha8Hgq4GU/s1600-h/MauiScoreBefore.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 398px;" src="http://1.bp.blogspot.com/_PtRfH0rESBo/SYlZgsf3S3I/AAAAAAAAABM/56Ha8Hgq4GU/s400/MauiScoreBefore.png" alt="" id="BLOGGER_PHOTO_ID_5298864854813592434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Note that all notes (with a few exceptions) are rendered as crotchets! The markup file is not much better, at 2,456 lines of this sort of stuff:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;...&lt;br /&gt;% 73&lt;br /&gt;e dis d cis c b4*128/960 s4*32/960 ais4*128/960 s4*32/960 a4*128/960&lt;br /&gt;s4*32/960 g4*128/960 s4*32/960 a4*128/960 s4*32/960 ais4*128/960&lt;br /&gt;s4*32/960 cis4*128/960 s4*32/960 d4*128/960 s4*32/960 a4*128/960&lt;br /&gt;s4*32/960 d4*128/960 s4*32/960 a'4*128/960 s4*32/960 f4*128/960&lt;br /&gt;s4*32/960 a4*128/960 s4*32/960 d4*128/960 s4*32/960 a4*128/960&lt;br /&gt;s4*32/960 f4*128/960 s4*32/960 a4*128/960 s4*32/960 f4*128/960&lt;br /&gt;s4*32/960 d4*128/960 s4*32/960 |&lt;br /&gt;% 74&lt;br /&gt;a4*384/960 s4*2256/960 e''4*192/960 s4*48/960 f4*128/960 s4*32/960 cis4*128/960&lt;br /&gt;s4*32/960 c4*128/960 s4*32/960 &amp;lt;c gis &amp;gt;4*128/960 s4*32/960 ais4*128/960&lt;br /&gt;s4*32/960 gis4*128/960 s4*32/960 |&lt;br /&gt;% 75&lt;br /&gt;&amp;lt;b g &amp;gt;4*128/960 s4*32/960 a4*128/960 s4*32/960 g4*128/960 s4*32/960 fis4*128/960&lt;br /&gt;s4*32/960 e4*128/960 s4*32/960 d'4*128/960 s4*32/960 e4*128/960&lt;br /&gt;s4*32/960 b4*128/960 s4*32/960 g4*128/960 s4*352/960 cis4*128/960&lt;br /&gt;s4*32/960 a,16 s16 a4*1152/960 s4*288/960 |&lt;br /&gt;% 76&lt;br /&gt;d,16 s16 d4*1152/960 s4*288/960 &amp;lt;a'' dis &amp;gt;4*256/960 s4*224/960 c,,4*1152/960&lt;br /&gt;s4*288/960 |&lt;br /&gt;% 77&lt;br /&gt;&amp;lt;dis'' a &amp;gt;4*256/960 s4*704/960 &amp;lt;fis, c' &amp;gt;4*256/960 s4*384/960 &amp;lt;fis c' &amp;gt;4*256/960&lt;br /&gt;s4*64/960 &amp;lt;a d &amp;gt;4*256/960 s4*224/960 d,,4*1152/960 s4*288/960 |&lt;br /&gt;% 78&lt;br /&gt;&amp;lt;e'' g &amp;gt;4*256/960 s4*704/960 &amp;lt;e g &amp;gt;4*256/960 s4*8384/960 d,,4*384/960&lt;br /&gt;s4*576/960 &amp;lt;d f &amp;gt;4*384/960 s4*576/960 |&lt;br /&gt;% 81&lt;br /&gt;&amp;lt;d f gis &amp;gt;4*384/960 s4*576/960 &amp;lt;gis f b &amp;gt;4*384/960 s4*576/960 &amp;lt;f a d &amp;gt;4*768/960&lt;br /&gt;s4*192/960 &amp;lt;e g d' &amp;gt;4*384/960 s4*96/960 &amp;lt;d' g, e &amp;gt;4*384/960 s4*96/960 |&lt;br /&gt;% 82&lt;br /&gt;&amp;lt;d g, e &amp;gt;4*384/960 s4*96/960 &amp;lt;e, g d' &amp;gt;4*384/960 s4*96/960 d'4*128/960&lt;br /&gt;s4*32/960 d4*128/960 s4*32/960 d4*128/960 s4*32/960 d4*128/960&lt;br /&gt;s4*32/960 d4*128/960 s4*32/960 d4*128/960 s4*32/960 &amp;lt;f, a d &amp;gt;8&lt;br /&gt;s8 &amp;lt;c' e e, &amp;gt;8 s8 |&lt;br /&gt;% 83&lt;br /&gt;...&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Split all instrumental parts into separate LilyPond files and include them (similar to #include in C/C++) in the master file, to make the score easier to work with.&lt;/li&gt;&lt;li&gt;Go through each file, correcting time signatures, note durations and removing unnecessary "s4"'s. Find &amp;amp; Replace worked to an extent, but each part took a while.&lt;/li&gt;&lt;li&gt;Convert chords into multiple-voice passages, keeping in mind that the order of notes in each chord is arbitrary from one chord to the next. Also keep in mind that changing the order of notes in a chord may disrupt the octave in 'relative pitch' mode, causing the rest of the music in that part to jump up or down an octave.&lt;/li&gt;&lt;li&gt;Fix octave pitch indicators where the music jumps up or down an octave. Note that this is an iterative process within each part.&lt;/li&gt;&lt;li&gt;Research and investigate the appropriate markup extensions to get the remaining layout 'good enough'. Very tricky in some cases.&lt;/li&gt;&lt;li&gt;Add dynamics and articulation marks to each part, and tempo indicators to the relevant parts (usually Flutes 1-2 and 1st Violins).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;At the end of this two-week process (I learnt the lesson of allocating more time from "Perpetual Restlessness") and yet another all-nighter, the LilyPond source looked a bit more meaningful (for those well-versed in LilyPond syntax):&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;...&lt;br /&gt;% 20  //Main melody 1/2 starts here&lt;br /&gt;\clef tenor&lt;br /&gt;&amp;lt;&amp;lt; {f'4( e f g | f2) r4 e8( d |&lt;br /&gt;c4 a'8. bes16 a8 g f e | f4 g f e} \\&lt;br /&gt;{d4( c d e | d2.) r4 |&lt;br /&gt;a1( | d2) (d4 c} &amp;gt;&amp;gt; |&lt;br /&gt;% 24  //Main melody 2/2&lt;br /&gt;&amp;lt;&amp;lt; {f4 e f) f( | g2. r4 |&lt;br /&gt;r2. a,4( | f2.) r4} \\&lt;br /&gt;{d'4 c d) d( | b2.) r4 |&lt;br /&gt;\clef bass&lt;br /&gt;r4 d( a e8. d16 | d2.) r4 } &amp;gt;&amp;gt; |&lt;br /&gt;% 28  //Variation A (p)&lt;br /&gt;R1*3 | r2. a'4(\( |&lt;br /&gt;% 32  //Variation A (ff-f)&lt;br /&gt;&amp;lt;f d'&amp;gt;2.) &amp;lt;f d'&amp;gt;8( &amp;lt;c' e,&amp;gt; |&lt;br /&gt;&amp;lt;d, bes'&amp;gt;2) r4 &amp;lt;d bes'&amp;gt;( |&lt;br /&gt;&amp;lt;e a&amp;gt;4) r4 &amp;lt;a c,&amp;gt;( &amp;lt;d, bes'&amp;gt; |&lt;br /&gt;&amp;lt;a' cis,&amp;gt;1)\) |&lt;br /&gt;% 36  //Variation B -&amp;gt; 'anchor drop' (End of Section I)&lt;br /&gt;a2 r8 a( bes g | a4) r4. bes8( a g |&lt;br /&gt;d4. e8 f g &amp;lt;d' bes&amp;gt; &amp;lt;g d&amp;gt; |&lt;br /&gt;&amp;lt;&amp;lt; {r2) \times 2/3 {f16[ g f} \times 2/3 {e d cis]}&lt;br /&gt;\times 2/3 {d[ e d} \times 2/3 {c bes a]} |&lt;br /&gt;r2 \times 2/3 {a16[ bes a} \times 2/3 {g a g]}&lt;br /&gt;\times 2/3 {f16[ g f} \times 2/3 {e f e]} | d1}&lt;br /&gt;\\&lt;br /&gt;{ r1 | \times 2/3 {bes'16[ c bes} \times 2/3 {a g f]}&lt;br /&gt;\times 2/3 {g[ a g} \times 2/3 {f e d]}&lt;br /&gt;\times 2/3 {f[ g f} \times 2/3 {e d c]}&lt;br /&gt;\times 2/3 {bes[ a g} \times 2/3 {a g e]} | d1 } &amp;gt;&amp;gt; |&lt;br /&gt;% 42  //Secondary theme (p)   (Section II - 'The Catch')&lt;br /&gt;\time 5/4&lt;br /&gt;...&lt;/blockquote&gt;It probably comes as little surprise from this (for those who know a bit of Maori mythology) that this piece is based on the &lt;a href="http://www.nzetc.org/tm/scholarly/tei-GrePoly-c1-2.html#n24"&gt;legend of Maui&lt;/a&gt; fishing up what became known as the North Island of New Zealand. Here's a part of the (somewhat more tolerable) output:&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PtRfH0rESBo/SYlZgn0sgmI/AAAAAAAAABU/e0J8OpukrVM/s1600-h/MauiScoreAfter.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 357px;" src="http://2.bp.blogspot.com/_PtRfH0rESBo/SYlZgn0sgmI/AAAAAAAAABU/e0J8OpukrVM/s400/MauiScoreAfter.png" alt="" id="BLOGGER_PHOTO_ID_5298864853558788706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;So what have I learned from all this?&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Know the true cost of what you're buying into&lt;/span&gt;.&lt;br /&gt;&lt;/div&gt;Cost isn't just measured in terms of money; it can also be measured in terms of other factors such as time and effort.&lt;br /&gt;&lt;br /&gt;So at the end of all this, I'm now the proud owner of a copy of Sibelius 5. Yes, it's expensive, but I've found that it is well worth it. Especially version 5, since the introduction of the Panorama view. Don't get me wrong - LilyPond itself has its merits, and it is admirable that a group of people have taken the time and effort to create this software, let alone for free. Rather than bashing LilyPond, I'm demonstrating that it is not ideal for composing or notating compositions when there are tight time pressures involved.&lt;br /&gt;&lt;br /&gt;After all, if you were composing a piece under similar circumstances, where would you want to spend your effort: composing or text-editing?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-4609654330562412865?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/4609654330562412865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=4609654330562412865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/4609654330562412865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/4609654330562412865'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2009/02/cost-of-open-source.html' title='The Cost of Open Source'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PtRfH0rESBo/SYlZgsf3S3I/AAAAAAAAABM/56Ha8Hgq4GU/s72-c/MauiScoreBefore.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-4365455916986384728</id><published>2008-12-18T22:05:00.009+13:00</published><updated>2009-02-01T19:00:38.878+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Building Multilingual WPF Applications</title><content type='html'>We've heard of the virtues of following the best practice of designing software to be as flexible as possible, namely ease of understanding and agility where maintenance is concerned. One dimension of this is localisation across multiple languages and cultures. That's one avenue I was wanting to explore in a WPF application that I've been working on. From a usability point of view, I wanted the following to be true:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Have one single version of the application that can cater for multiple languages. This means no separate English version, French version, Japanese version, etc. - think of many electronic products being produced, which support multiple languages. You don't have to buy a slightly different model to have your native language, nor have to apply different firmware patches to have a different language to what is installed by default.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make it easy for users to change the interface language at runtime. No need to close the application, configure the culture of the operating system, or manually load resources for your own language.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;When the application starts for the first time, its interface is in the system language specified by the operating system. This makes sense - French users would want to install, run and use the software right away; not try to navigate an unfamiliar application to change the language before being able to use it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The interface would still be able to stand up to translated text that would be of different lengths between languages. Fortunately, the flexibility of WPF makes this a piece of cake.&lt;/li&gt;&lt;/ul&gt;With that covered, the following are the aspects of the design I came up with to achieve these goals.&lt;br /&gt;&lt;h4&gt;XML-based Language Definitions&lt;/h4&gt;Every single piece of text that forms the user interface is stored in localised form in an XML file for each language, with all XML files compiled as an embedded resource. The element name surrounding each piece of text determines what the text represents, i.e. it is used as a lookup to retrieve the localised text. Here's an example of the English definition, LangEN.xml:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&amp;lt;LangSettings&amp;gt;&lt;br /&gt;    &amp;lt;IsRtl&amp;gt;0&amp;lt;/IsRtl&amp;gt;&lt;br /&gt;    &amp;lt;MinFontSize&amp;gt;11&amp;lt;/MinFontSize&amp;gt;&lt;br /&gt;    &amp;lt;HeadingFontSize&amp;gt;16&amp;lt;/HeadingFontSize&amp;gt;&lt;br /&gt;    &amp;lt;UIText&amp;gt;&lt;br /&gt;        &amp;lt;!-- Menu bar --&amp;gt;&lt;br /&gt;        &amp;lt;SettingsLabel&amp;gt;Settings&amp;lt;/SettingsLabel&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;!-- Settings --&amp;gt;&lt;br /&gt;        &amp;lt;AppBehaviourSectionLabel&amp;gt;Application Behaviour&amp;lt;/AppBehaviourSectionLabel&amp;gt;&lt;br /&gt;        &amp;lt;LanguageSectionLabel&amp;gt;Language&amp;lt;/LanguageSectionLabel&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;!-- Common Operations --&amp;gt;&lt;br /&gt;        &amp;lt;ApplyLabel&amp;gt;Apply&amp;lt;/ApplyLabel&amp;gt;&lt;br /&gt;        &amp;lt;ApplyCurrentLabel&amp;gt;Apply Current&amp;lt;/ApplyCurrentLabel&amp;gt;&lt;br /&gt;        &amp;lt;ApplyAllLabel&amp;gt;Apply All&amp;lt;/ApplyAllLabel&amp;gt;&lt;br /&gt;        &amp;lt;UndoCurrentLabel&amp;gt;Undo Current&amp;lt;/UndoCurrentLabel&amp;gt;&lt;br /&gt;        &amp;lt;UndoAllLabel&amp;gt;Undo All&amp;lt;/UndoAllLabel&amp;gt;&lt;br /&gt;        &amp;lt;CancelLabel&amp;gt;Cancel&amp;lt;/CancelLabel&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/UIText&amp;gt;&lt;br /&gt;&amp;lt;/LangSettings&amp;gt;&lt;/blockquote&gt;In the English example above, also notice the IsRtl, MinFontSize and HeadingFontSize elements. The font sizes are used to determine what size to render the fonts for better legibility, especially when displaying text in Japanese, Korean and Arabic, for example. The IsRtl element indicates whether the language reads right-to-left (as is the case for Arabic and Hebrew).&lt;br /&gt;&lt;br /&gt;Notice that the language name is not given in this XML. This is because the localised language names are defined in a separate XML file, LanguageNames.xml:&lt;br /&gt;&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&amp;lt;LangNames&amp;gt;&lt;br /&gt;    &amp;lt;LangEN&amp;gt;English&amp;lt;/LangEN&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;LangAR&amp;gt;العربية&amp;lt;/LangAR&amp;gt;&lt;br /&gt;    &amp;lt;LangDE&amp;gt;Deutsch&amp;lt;/LangDE&amp;gt;&lt;br /&gt;    &amp;lt;LangEL&amp;gt;Ελληνικά&amp;lt;/LangEL&amp;gt;&lt;br /&gt;    &amp;lt;LangES&amp;gt;Español&amp;lt;/LangES&amp;gt;&lt;br /&gt;    &amp;lt;LangFR&amp;gt;Français&amp;lt;/LangFR&amp;gt;&lt;br /&gt;    &amp;lt;LangIT&amp;gt;Italiano&amp;lt;/LangIT&amp;gt;&lt;br /&gt;    &amp;lt;LangJP&amp;gt;日本語&amp;lt;/LangJP&amp;gt;&lt;br /&gt;    &amp;lt;LangKO&amp;gt;한국어&amp;lt;/LangKO&amp;gt;&lt;br /&gt;    &amp;lt;LangRU&amp;gt;Русский&amp;lt;/LangRU&amp;gt;&lt;br /&gt;    &amp;lt;LangSV&amp;gt;Svenska&amp;lt;/LangSV&amp;gt;&lt;br /&gt;&amp;lt;/LangNames&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;Also note that the element names correspond to the name of each language definition file. The decision to name the elements in the form 'Lang&lt;span style="font-style: italic;"&gt;XX&lt;/span&gt;', where &lt;span style="font-style: italic;"&gt;XX&lt;/span&gt; denotes the two-letter ISO language name, is intentional.&lt;br /&gt;&lt;h4&gt;Internal State&lt;/h4&gt;Inside the application there are a number of entities forming the state relating to interface language. Firstly, the language information is stored in a UILanguageDefinition class, which contains the contents of the Lang&lt;span style="font-style: italic;"&gt;XX&lt;/span&gt; XML file that has been loaded. The XML elements inside &lt;uitext&gt; are stored in a Dictionary&lt;string, string=""&gt;, for efficient lookup of the actual text. Since only one language would be displayed in the application (except for the language selection list), only one instance of this would be loaded at once to help keep the memory footprint small.&lt;br /&gt;&lt;br /&gt;The second major entity is the application-wide state, forming part of the 'M' in MVP. This contains the authoritative instance of the UILanguageDefinition being used by the entire application. It is this instance that gets bound to the text elements in the entire UI.&lt;br /&gt;&lt;br /&gt;The application-wide state also contains a third major entity - the settings state. It is this state that stores the current interface language being used, as well as a reference to the list of languages to display in the Languages tab of the Settings panel. With the exception of this list, all settings are persisted to disk when the application is closed, and reloaded when the application is next opened. However, if the application is being loaded for the first time (and no settings file exists), these have to be reset to defaults.&lt;br /&gt;&lt;br /&gt;For languages, it would be easiest to make English the default, but this isn't user-friendly. Instead, the current system language is queried by retrieving:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;CultureInfo.CurrentCulture.TwoLetterISOLanguageName;&lt;br /&gt;&lt;/blockquote&gt;and looking up the corresponding language. If the language isn't supported by the application, English is then used as the default. This way, as long as your native language is supported, the UI will be displayed in your native language when you first run the application.&lt;br /&gt;&lt;h4&gt;The UI&lt;/h4&gt;So far, this implementation has been agnostic of whether WPF is being used (as opposed to WinForms, etc.), but there are clear advantages to using WPF based on how easy it is to change the entire interface language through the use of data binding.&lt;br /&gt;&lt;br /&gt;Essentially, data binding allows the entire interface to change as the result of changing one reference - that of the underlying UILanguageDefinition being used. This is reference is stored on the main application window, MainWindow, as a DependencyProperty. To support data binding, a DependencyProperty should be used instead of an ordinary property. In this example, the property is named "currentLanguage".&lt;br /&gt;&lt;br /&gt;Whenever text is being set in XAML, e.g: "Apply All", the binding expression given is:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&amp;lt;TextBlock Text="{Binding Path=currentLanguage, Converter={StaticResource uiText},&lt;br /&gt;        ConverterParameter=ApplyAllLabel,&lt;br /&gt;        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type uiCt:MainWindow}}}" /&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;Breaking this expression down, 'currentLanguage' is the DependencyProperty of the same name in MainWindow. To successfully retrieve it, the RelativeSource needs to be specified - in this case it uses the FindAncestor mode to access the MainWindow. These attributes are constant throughout the entire application.&lt;br /&gt;&lt;br /&gt;Remember that 'currentLanguage' is a UILanguageDefinition, not a string as expected by the Text property, therefore a value converter is needed to do this transformation. This converter uses a ConverterParameter to specify the lookup key to retrieve the corresponding localised piece of text (which is stored in a Dictionary). The beauty of this is that for every new piece of text to localise in the interface, the corresponding element needs to be added to the language XML files, making sure that the ConverterParameter and element name matches. No additional properties need to be defined in between - whether in MainWindow or UILanguageDefinition.&lt;br /&gt;&lt;br /&gt;The converter itself is relatively straightforward. All it needs to do is implement IValueConverter (System.Windows.Data), specify the ValueConversion attribute at the class level:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;[ValueConversion(typeof(UILanguageDefn), typeof(string))]&lt;/blockquote&gt;and implement the Convert function as follows:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;public object Convert(object value, Type targetType, object parameter, CultureInfo culture)&lt;br /&gt;{&lt;br /&gt;    string key = parameter as string;&lt;br /&gt;    UILanguageDefn defn = value as UILanguageDefn;&lt;br /&gt;&lt;br /&gt;    if (defn == null || key == null || !defn.text.ContainsKey(key)) return "";&lt;br /&gt;&lt;br /&gt;    return defn.text[key];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;Tidying up, the converter is declared as a shared resource with key "uiText", and the appropriate XML namespaces are defined at the root node of the applicable XAML documents.&lt;br /&gt;&lt;br /&gt;Putting it all together, here are the results:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;English &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtKHmsqKI/AAAAAAAAABE/BDuto9eNqEk/s1600-h/MultiLingual-EN.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 301px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtKHmsqKI/AAAAAAAAABE/BDuto9eNqEk/s400/MultiLingual-EN.png" alt="" id="BLOGGER_PHOTO_ID_5297690188534556834" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;French &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PtRfH0rESBo/SYUtJqTUa3I/AAAAAAAAAAs/rTN9QPbaOJc/s1600-h/MultiLingual-FR.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 301px;" src="http://2.bp.blogspot.com/_PtRfH0rESBo/SYUtJqTUa3I/AAAAAAAAAAs/rTN9QPbaOJc/s400/MultiLingual-FR.png" alt="" id="BLOGGER_PHOTO_ID_5297690180668648306" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Japanese &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtJgDG45I/AAAAAAAAAA0/lEZWItqfZE0/s1600-h/MultiLingual-JA.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 301px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtJgDG45I/AAAAAAAAAA0/lEZWItqfZE0/s400/MultiLingual-JA.png" alt="" id="BLOGGER_PHOTO_ID_5297690177916298130" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Russian &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtKCOMqBI/AAAAAAAAAA8/aXzr3CtKFeM/s1600-h/MultiLingual-RU.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 301px;" src="http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtKCOMqBI/AAAAAAAAAA8/aXzr3CtKFeM/s400/MultiLingual-RU.png" alt="" id="BLOGGER_PHOTO_ID_5297690187089618962" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Notice how the UI elements dynamically resize to fit the content - this is achieved by following the best practice of &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; specifying explicit widths and heights of elements. Instead, appropriate spacing is achieved through the Margin and Padding properties. The layout system used in WPF allows the desired size of elements in the visual hierarchy to determine the final size, including where grid columns and rows have their width/height property set to 'Auto'.&lt;br /&gt;&lt;br /&gt;So where to from here? At the moment we have localised text being displayed in the UI, and the font sizes defined in the language XML files are being honoured by similar binding expressions in the TextBlock styles (achieved via the FindAncestor mode to retrieve 'currentLanguage.minFontSize', etc. from the MainWindow - hence no need to use a value converter). The only thing that remains is to reverse the entire interface for Right-to-Left languages, so that the logical progression of the interface reflects the reading order.&lt;br /&gt;&lt;/string,&gt;&lt;/uitext&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-4365455916986384728?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/4365455916986384728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=4365455916986384728' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/4365455916986384728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/4365455916986384728'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2008/12/building-multilingual-wpf-applications.html' title='Building Multilingual WPF Applications'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_PtRfH0rESBo/SYUtKHmsqKI/AAAAAAAAABE/BDuto9eNqEk/s72-c/MultiLingual-EN.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-1102030305252795664</id><published>2008-09-12T17:36:00.003+12:00</published><updated>2008-09-12T17:50:02.593+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Usability'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Building Software With Smarts</title><content type='html'>&lt;p&gt;Two of the things I enjoy most about software development are problem-solving and adding value. The problem-solving aspect gives me the mental stimulation that I enjoy, as well as the buzz of being innovative. However, the notion of creating value is what makes it worthwhile. But what exactly does it mean to create value, and how can this value be increased? I'm not talking about simply making the software fulfil a set of requirements or functional specifications for a target customer, I'm talking about those non-functional aspects that can determine whether the software is helpful and a joy to use, or some obstacle that becomes a burden that one is obliged to use (because there are aspects that are depended on).&lt;/p&gt;&lt;p&gt;Actually adding value requires us to look beyond the airy-fairy world of buzzwords and focus on real, measurable aspects such as performance, flexibility and ease-of-use. Achieving them doesn't need to consume significantly more time and budget to achieve if the mindset is there from the start. For me in the thick of it, my mindset isn't based on the question, "How can I maximise the value?" Instead I ask questions like:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How would I solve this problem as a human being?&lt;/li&gt;&lt;li&gt;How would I expect to use this software as easily, yet effectively as possible?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;By asking these sorts of questions, I'm more easily equipped to come up with an appropriate implementation that gives the software a greater degree of smarts, which in turn achieves a combination of factors like improved performance, greater flexibility and usability. This increases the value as a result, and makes the effort worthwhile.&lt;/p&gt;&lt;p&gt;As a recent example, I was involved in a piece of work that I can be proud of despite the challenges that arose – simply because I designed the solution from the outset for flexibility. This was prompted by receiving fuzzy requirements at the outset that indicated a strong certainty of changes being required at a later stage. The task was to create a back-end system that receives mapping data in &lt;a href="http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm"&gt;CSV format&lt;/a&gt; for each part of a batch production process, and store these mappings in a database for later retrieval by another component of the solution.&lt;/p&gt;&lt;p&gt;The biggest challenge was that fields to be mapped between tables had different column names in the respective CSV files, and these usually couldn't be changed as they came from independent suppliers. As indicated previously, there was also a strong likelihood of these field names changing as the project gained momentum, especially since the details of the requirements were fuzzy as a result of this project being new for the client and their suppliers.&lt;/p&gt;&lt;p&gt;Whatever the changes, the software solution should remain flexible and not require significant internal changes (that would require redeployment) to adapt – especially if the functionality was to be exactly the same. Internally, the terminology for business entities and attributes remained consistent, while the different CSV field names were stored in the human-editable configuration file as aliases to these internal attributes.&lt;/p&gt;&lt;p&gt;For a developer, it might be tempting to create a whole bunch of different settings, one for each field alias with setting names as methodical as "EntityAField1Alias". However as someone filling in the values, I don't want to maintain a whole bunch of settings if one will do, and I like any necessary instructions to be as handy as possible (e.g. embedded in the comments) for reference. In my perspective, the goal was to store a set of mappings from an internal field to a set of alias mappings, and let the internal workings handle the reading of that. So instead of storing many individual aliases, I stored a set of alias mappings. This becomes a bit more user-friendly from closer alignment to the business problem domain, as well as having the flexibility to cope with multiple aliases. As an aside, it was rather fun using &lt;a href="http://www.regular-expressions.info/"&gt;regular expressions&lt;/a&gt; to extract these mappings and the aliases inside them, though non-developers don't need to know about the technical intricacies, let alone what regular expressions are.&lt;/p&gt;&lt;p&gt;As a result, the solution adapted to changes in the input specification with ease, thereby requiring very little time for re-work and no need to recompile or redeploy the solution. This was invaluable when such a change occurred at the last minute – a true example of being agile. In the long run, if this client needs to have further changes made, having such a flexible design will certainly save them money.&lt;/p&gt;&lt;p&gt;Of course, flexibility is only one benefit of building greater smarts into software. Another is performance.&lt;/p&gt;&lt;p&gt;Take Sudoku for example. There are many implementations of Sudoku out there, as one can see online in programming articles, source repositories and commercial sites. From what I've seen, a great many solve these by brute force – guessing numbers as long as they fit, and backtracking if necessary. This can take a very long time to complete. I myself wrote a solver back in 2005 while at university, using logical deduction and elimination to decide where to place numbers. Given a puzzle (from the newspaper) as input via text file, my solver was able to solve it instantly. Even a 16x16 'hard' Sudoku puzzle was able to be solved in less than half a second on an average PC – much to the amazement of my peers.&lt;/p&gt;&lt;p&gt;How did I do this? I looked at the way I solve Sudoku puzzles, and translated that into code. I don't randomly choose numbers and see where they fit, instead I look at each cell and work out the possible numbers that could be placed there. The first two logical rules for simplifying these sets of 'candidate' numbers are the easiest: finding cells with only one candidate, and finding candidates that appear only once in any given region (row, column, or rectangle). The latter is the easiest to apply visually, while the former requires more mental effort because of counting.&lt;/p&gt;&lt;p&gt;Naturally, computers are much faster than us at doing this, but only as smart as what they are programmed to do. The big challenge is how to capture our own smarts and translate what comes naturally into code. From experience, a good (though maybe obvious) strategy is to divide the problem into manageable sub-problems and conquer each of them individually. This not only encourages well-structured code (busting the myth that smarter software is unreadable or harder to maintain), but it also achieves these aspects that increase value in a more productive manner.&lt;/p&gt;&lt;p&gt;When working on your current or next project, know the problem and its sub-problems you are trying to solve, and try to keep this question in mind:&lt;/p&gt;&lt;p&gt;"How would I do this myself?"&lt;/p&gt;&lt;p&gt;And remember - the more smarts, the better.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-1102030305252795664?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/1102030305252795664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=1102030305252795664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1102030305252795664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1102030305252795664'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2008/09/building-software-with-smarts.html' title='Building Software With Smarts'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-8728033954675896036</id><published>2008-09-11T21:01:00.005+12:00</published><updated>2008-09-12T00:37:35.618+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Music'/><category scheme='http://www.blogger.com/atom/ns#' term='Hardware'/><category scheme='http://www.blogger.com/atom/ns#' term='General'/><category scheme='http://www.blogger.com/atom/ns#' term='Travel'/><title type='text'>Where have I been?</title><content type='html'>Well I haven't spent all my time playing Crysis. :-)&lt;br /&gt;&lt;br /&gt;It came as a bit of a shock to find that it has been a long time since my previous post about trying Crysis on a machine below specifications, and I've been occupied with so much since then - not just to do with programming. Naturally I needed to upgrade my machine to cope with the demands of certain software, plus I was due for a RAM upgrade anyway.&lt;br /&gt;&lt;br /&gt;Well, what a saga that was. Most RAM nowadays is DDR2, which requires a slightly different motherboard slot design, so that prompted a motherboard upgrade as well. While I was at it, I upgraded the CPU to an Athlon64 dual core (which is also handy for taking advantage of applications that support parallel processing). This narrows down the choices of motherboards available (that I could order through &lt;a href="http://www.ascent.co.nz"&gt;Ascent&lt;/a&gt;), most of which were also designed for PCIe-16 graphics cards. You guessed it - a graphics card upgrade as well. At the end of that I had enough to get decent performance from Crysis, among other things. Oh yes, I also upgraded the case to one with better airflow.&lt;br /&gt;&lt;br /&gt;Remember Murphy's Law? If something can go wrong it will. The motherboard is what went wrong - an Asus M2N-SLI Deluxe. I narrowed that down after running MemTest, upgrading the power supply to a 620W model and stress-testing the CPU. It often seemed to happen when sound was playing, though not always. The computer would freeze, prompting a reboot, but the BIOS wouldn't boot. Turning the power off and on again was the only thing that would allow me to carry on.&lt;br /&gt;&lt;br /&gt;The good thing is I received a replacement that seemed to work - until it locked up the system when I tried to timeshift or record TV programmes. It also froze when trying to record my music through the soundcard (more on that later), so back that motherboard went. This time I replaced it with a Gigabyte model that has been running fine since. Third time lucky!&lt;br /&gt;&lt;br /&gt;Around the time of the upgrade, I received a letter from the &lt;a href="http://www.nzso.co.nz/"&gt;NZSO&lt;/a&gt; letting me know of another chance to showcase my music composition - the National Youth Orchestra (NYO) &lt;a href="http://www.nzso.co.nz/education/young_composers#nyo"&gt;Composer-in-Residence&lt;/a&gt;. Previously, I had entered the Young Composer Awards with my piece, "Perpetual Restlessness". Although my piece wasn't among those selected for orchestral readings in September last year, the feedback provided helpful hints as to what to look out for when writing music.&lt;br /&gt;&lt;br /&gt;Using this knowledge, plus what I learned from reading Professor Belkin's &lt;a href="http://www.garritan.com/Orchestration_Tutorial.html"&gt;Artistic Orchestration&lt;/a&gt; tutorial and Rimsky-Korsakov's &lt;a href="http://www.northernsounds.com/forum/forumdisplay.php?f=77"&gt;Principles of Orchestration&lt;/a&gt;, I worked on a new piece titled "Maui", after the character from Maori legend. This work is a tone poem that describes the story of Maui setting out and &lt;a href="http://www.teara.govt.nz/1966/M/MauiLegendsOf/TheFishOfMaui/en"&gt;fishing&lt;/a&gt; up what becomes known as the North Island of New Zealand. Rather than portaying Maui's prankster nature, this piece focuses on Maui's strength and determination through its regular beat and strong tonal theme.&lt;br /&gt;&lt;br /&gt;Most recently, I have finished assisting my grandmother in putting together a short documentary-style film commemorating the work of a non-profit community organisation in Wellington over the past 125 years. I have to say it is wonderful for my grandparents (nearly 80 years old) to be tech-savvy enough to perform movie editing, of all things. They even have the initiative to seek help on Internet discussion forums! I know of many at that age who are bewildered and somewhat intimidated by today's technology. Nevertheless, it isn't helpful when the movie editing software being used is somewhat defective - which is why I was called in to help.&lt;br /&gt;&lt;br /&gt;This basically involved recording my mother's narration and placing it in the movie, adding background music, titles and credits. Under request from my grandmother, my composition "Cathedral" was also used for the end of the film.&lt;br /&gt;&lt;br /&gt;Finally, to answer "Where have I been" literally: I can now say that I've been to London, Paris, Lucerne, Nice, Pisa, Florence, Rome, Verona (think Romeo &amp;amp; Juliet), Venice, Hopfgarten, Munich, Vienna, Prague, St Goar and Amsterdam. Yes, I went on a Contiki tour of Europe from mid-June to mid-July. The tour I chose was the 21-day European Vista, which turned out to be a good length of time - long enough to really make the most of Europe and get to know everybody, yet short enough to not get too run-down from the late nights and early mornings. One of my main reasons for choosing this tour was that it visited Vienna, the hub for famous composers such as Haydn, Mozart and even Beethoven for a significant period of their lives. It was a classic (excuse the pun) to attend a concert in that very city. That obviously wasn't the only highlight - there were good times with the group in Lucerne, paragliding in the Austrian Tyrol and spending the last moments of the tour in Amsterdam.&lt;br /&gt;&lt;br /&gt;The interesting thing is that my tour group consisted of mostly Australians, which I guess is rather handy being in (relatively) close proximity - it's quite a bit easier to catch up in person. As a few people who have been on such tours in the past, it is a great opportunity to see the sights, meet new people and have memorable experiences. Believe me, there were a few - such as getting lost in Paris on my own without a map (a great chance to see the 'real' Paris while exercising resourcefulness), working through the language barrier in rural Italy when locals don't speak English (it helps to remember the Italian words used in music as well as the basic phrases), and getting the reception of a rock star from singing "Sweet Child of Mine" at a karaoke nightclub in Florence. Yes, it was hard recovering afterwards (i.e. getting back into the routines), but the trip was definitely worth it with much gained. As one colleague put it - an experience of a lifetime.&lt;br /&gt;&lt;br /&gt;Well they say that variety is certainly the spice of life, and the diversity of this post would indicate I'm enjoying a lot of spice. Next up: preparing for our next social/musical event at work - Rocktober!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-8728033954675896036?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/8728033954675896036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=8728033954675896036' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/8728033954675896036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/8728033954675896036'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2008/09/where-have-i-been.html' title='Where have I been?'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-1003511049839570501</id><published>2007-11-24T23:47:00.000+13:00</published><updated>2007-11-25T02:23:43.458+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Games'/><title type='text'>Crysis below minimum specs - Will It Play?</title><content type='html'>&lt;p&gt;The waiting is over - Crysis has finally been released here in NZ. Having played and really enjoying Far Cry, I couldn't resist getting the Special Edition of Crysis (for the same cost as the standard edition at most other retail outlets). Plus being a limited edition, it wasn't going to hang around forever when the cost comes down to around $20-40.&lt;/p&gt;&lt;p&gt;Anyway, much has been hyped about the spectacular, near photo-realistic graphics, with the cost of this being made all too clear - prompting many to consider upgrades of their graphics cards at least. The main system requirements, as many will know, are a little steep (though people said the same when Unreal first came out all those years ago):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Processor - Pentium 4 2.8GHz / AthlonXP 2800+ or faster&lt;/li&gt;&lt;li&gt;RAM - at least 1.0GB&lt;/li&gt;&lt;li&gt;HDD space - 12GB&lt;/li&gt;&lt;li&gt;Graphics card - GeForce 6800GT / Radeon X800 or better with at least 256MB video RAM&lt;/li&gt;&lt;li&gt;DirectX 9.0c&lt;/li&gt;&lt;/ul&gt;These are based on running Windows XP. Vista demands a bit more, e.g. 1.5GB RAM.&lt;br /&gt;&lt;p&gt;For me, RAM was always going to be the next thing to upgrade. Currently I've been running a computer that has evolved over the years since the original machine I bought in 2001. That consisted of an Athlon 1400, 512MB RAM, a GeForce2 MX 400, and running (shock, horror) Windows ME. Now it is technically a completely different machine since the major upgrade of 2004. It currently sports:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;AMD Athlon 2600+ (Barton core)&lt;/li&gt;&lt;li&gt;512MB DDR-400 RAM (dual channel)&lt;/li&gt;&lt;li&gt;250GB 7200rpm HDD with Windows XP SP2&lt;/li&gt;&lt;li&gt;GeForce 6600GT with 128MB video RAM (8x AGP)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Obviously, this doesn't quite meet the minimum requirements. The CPU is slightly slower, the graphics chip is a slightly lower revision, but the glaring difference is that I have &lt;i&gt;half&lt;/i&gt; the RAM required. The same also holds for the amount of video RAM.&lt;/p&gt;&lt;p&gt;This all leads to one conclusion - it's upgrade time!&lt;/p&gt;&lt;p&gt;New RAM has been ordered, along with an Athlon64 X2 CPU, and a new motherboard, and a new video card. In the meantime, while I'm waiting all the parts to arrive, Crysis has already been delivered. The anticipation is building. I've watched the special features, listened to the soundtrack CD. The anticipation builds some more.&lt;/p&gt;&lt;p&gt;I have Crysis. And a machine below the minimum spec. That just leaves one question:&lt;/p&gt;&lt;p&gt;&lt;b&gt;Will it play?&lt;/b&gt;&lt;/p&gt;&lt;p&gt;The first thing was to install it on my machine. The installer was launched by a disc menu launcher that had no problems running. No checks were made of my hardware to see if it was up to running Crysis, so on it went allowing me to install the game.&lt;/p&gt;&lt;p&gt;The interesting thing is that the custom installation mode allows you to deselect items to install, whether it be localisation data for the game to run in other languages, or the PunkBuster anti-cheat software for Internet-based multiplayer modes. Having deselected all languages apart from English, the game took up just over  6GB on the hard drive. That's only half the 'required' disk space! Though I guess part of that figure is to allow for in-game caching, saved game files, and the Windows swap file.&lt;/p&gt;&lt;p&gt;Once the game was installed, the next major test was to launch it. After a bit of time loading the game from disk (not too long), the screen went dark, switched resolution and started playing the Crytek intros. These ran quite smoothly, probably since they were cinematic videos rather than dynamically-rendered 3D content.&lt;/p&gt;&lt;p&gt;The main menu, in its futuristic 'military green' theme, showed with no problems either. Before launching into the game itself, I thought I'd go into the settings and see what graphics settings had been assigned by default. As expected, it had figured out that the computer hardware wasn't really 'up to it', and had therefore set everything to the lowest possible quality settings (and the resolution to 800x600). After a few tweaks to volume levels and key mappings, it was time for the real test - starting a new game.&lt;/p&gt;&lt;p&gt;The loading screen for the first level, "Contact", had a progress bar that moved just as fast, but at a more consistent pace than for levels in Far Cry. Near the end of loading, though, it slowed down noticeably, but not by too much. Once it reached 100%, it stayed there for quite a while - at least half as long again. The hard disk was being accessed constantly, indicating that there was a huge amount of paging going on. This highlighted the most significant deficiency of my machine - that 512MB really was far too little to meet the demands of the game and the underlying operating system.&lt;/p&gt;&lt;p&gt;Once the loading finished, the cinematic sequence began. The first part of it, with the voice acting of Helena over the radio, ran quite smoothly. However, the opening action scene (with the captain's briefing) had quite a few skipped frames. Considering that this was on the lowest quality settings available, the graphics were quite good. I have to admit that the result of facial motion capture drew so much attention that one didn't necessarily notice any lack of definition in the textures on the far wall of the plane. From here to well into the level (once landing on the island) there were a few periods of jitter while background processing was being performed. At one stage the screen froze for quite a long period while the OS was paging to/from disk, also causing the sound to stutter for around two seconds before smooth gameplay resumed.&lt;/p&gt;&lt;p&gt;There were also some interesting artifacts observed. Firstly, the resulting computations performed when shooting trunks of palm trees caused a bit of jitter and skipped frames. In a nearby area of rocks, the simple act of turning on the spot caused a previously invisible small rock to suddenly appear out of nowhere. This seemed comparable to some observed artifacts in Far Cry, where textures on rocks or hills shifted as one approached them. The worst artifact, though, was the sudden appearance of a bright blue rectangular plane (random bluescreen!) in the mid-distance on the beach.&lt;/p&gt;&lt;p&gt;These artifacts suggest that the cause may likely be RAM-related. The shooting of trunks would likely cause recalculation of the tree geometry and introduce additional physics parameters, thus consuming more RAM and causing paging. It is also possible that the processing power of both the CPU and graphics processor may have contributed to uneven simulation of the falling treetop. Shifting textures / noticeable changes in level of detail (LOD) could be attributed to lack of video RAM, since the graphics card is where one would expect most of the geometry and texture processing to take place. The RAM situation must have been very dire for a random bluescreen to be displayed - that not even geometry could be computed with no texture applied.&lt;/p&gt;&lt;p&gt;Once I reached a checkpoint I decided to call it a day (and possibly wait to perform the upgrade). Quite a bit more paging occured in the transition from the in-game menu to the main menu, and about as much again when exiting the game altogether. Back in Windows, I noticed a yellow warning triangle in the system tray. Guess what it's tooltip said? "Virtual memory too low." Funny, that.&lt;/p&gt;&lt;p&gt;So what conclusions can we draw from this? If you haven't guessed, the amount of RAM plays a significant part in the performance of the system, especially when things start getting paged to disk. Despite the slowdowns, though, the game remains largely playable despite the occasions where skipped frames and jittery visuals compromise the user experience. The minimum requirements aren't necessarily a hard-and-fast limit that is strictly enforced, but more of a guide as to what to expect for reasonable performance at minimum settings. If you analyse the percentage difference between the current machine specs and the minimum requirements,  the CPU speed is nearly there at 92% (1.92GHz / 2.08GHz), graphics processor at 71.4% (estimated by relative clock speed in MHz times number of processors/pipelines*) but both RAM and video RAM are only at 50% - a big difference. And it shows.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;* Figures obtained from &lt;a href="http://en.wikipedia.org/wiki/GeForce_6"&gt;Wikipedia&lt;/a&gt;.&lt;br /&gt;6600GT: 500MHz core x 8 pixel shaders/pipelines&lt;br /&gt;6800GT: 350MHz core x 16 pixel shaders/pipelines&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-1003511049839570501?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/1003511049839570501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=1003511049839570501' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1003511049839570501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1003511049839570501'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/11/crysis-below-minimum-specs-will-it-play.html' title='Crysis below minimum specs - Will It Play?'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-5292241271101557319</id><published>2007-09-08T20:41:00.000+12:00</published><updated>2007-09-08T22:32:18.875+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tech-Ed'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Workflow Foundation'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Reflections on Tech-Ed 2007 - Part 5</title><content type='html'>This is the last post in the series on the Tech-Ed 2007 highlights, covering the remaining two technical sessions.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;DEV313 – LINQ Deep Dive&lt;/h4&gt;While the title of this session implies an exclusive coverage of &lt;a href="http://msdn2.microsoft.com/en-gb/netframework/aa904594.aspx"&gt;LINQ&lt;/a&gt; (Language Integrated Query) being introduced in &lt;a href="http://download.microsoft.com/download/9/5/0/9503e33e-fde6-4aed-b5d0-ffe749822f1b/csharp%203.0%20specification.doc"&gt;C# 3.0 [338kB DOC]&lt;/a&gt; (part of .NET 3.5), the session itself provided much more value by covering pretty much all of the other new language features in C# 3.0. The presenter, &lt;a href="http://www.base4.net/blog.aspx"&gt;Alex James&lt;/a&gt;, cleverly snuck in these language features by showing how the LINQ syntax evolved from a .NET 2.0 implementation of a data query with generics (the C# equivalent of C++ templates).&lt;br /&gt;&lt;br /&gt;Here are the new language features introduced along the way:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Extension Methods&lt;/span&gt;. By adding the 'this' keyword to a method parameter (preferably the first), the method can be called as if it belonged to the class of that parameter. For example, with an extension method:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;public static IEnumerable&amp;lt;T&amp;gt; Where(this IEnumerable&amp;lt;T&amp;gt; source, Predicate&amp;lt;T&amp;gt; filter) {...}&lt;/span&gt;&lt;/blockquote&gt;the function can be called on 'source':&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;blockquote&gt;return sampleSource(sampleFilter);&lt;/blockquote&gt;&lt;/span&gt;as well as in the traditional way:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;blockquote&gt;return DataUtils.Where(sampleSource, sampleFilter);&lt;/blockquote&gt;&lt;/span&gt;Thus the extension method appears to be part of &lt;span style="font-family:courier new;"&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/span&gt;. This helps similar calls to be chained instead of nested.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Lambda Expressions&lt;/span&gt;. This provides a short-hand notation for defining anonymous delegates. For example, given a delegate defined as:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;public delegate bool Predicate&amp;lt;T&amp;gt;(T t);&lt;/blockquote&gt;an instance of this delegate can be defined as:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;Predicate&amp;lt;GPFunction&amp;gt; chainableFilter = fn =&gt; fn.NumOfChildren &gt; 1 &amp;&amp;amp; fn.ReturnType == fn.ChildSpec[0].ReturnType;&lt;/blockquote&gt;instead of:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;Predicate;GPFunction&amp;gt; chainableFilter = new delegate(GPFunction fn)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; return (fn.NumOfChildren &gt; 1 &amp;&amp;amp; fn.ReturnType == fn.ChildSpec[0].ReturnType);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;* If anyone is wondering what GPFunction, etc. is all about, feel free to read my Computer Science for Honours &lt;a href="http://www.mcs.vuw.ac.nz/%7Emengjie/students/daniel.pdf"&gt;thesis&lt;/a&gt;&lt;a href="http://www.mcs.vuw.ac.nz/%7Emengjie/students/daniel.pdf"&gt; [910kB PDF]&lt;/a&gt; on &lt;a href="http://www.genetic-programming.org/"&gt;Genetic Programming&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Implicit Typing&lt;/span&gt;. This introduces the var keyword, which is used just like in JavaScript. While it may seem strange to introduce late binding of data types when strong typing is already present, it becomes very helpful when anonymous types are used (explained next). Once a type has been bound, that variable cannot be assigned a new type.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Anonymous Types&lt;/span&gt;. This is a logical extension of anonymous delegates, applied to data types in general. It allows declaration of lightweight data structures (i.e. tuples) without having to specify a full class or struct:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;var dataItem = new {Name = "ClassName", Type = DataTypes.String};&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;var duplicateItem = new {Name = dataItem.Name, Type = dataItem.Type};&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;In the evolution of LINQ example, anonymous types were used in the definition of the Where extension method, considering that the programmer can select any number of properties in any order (as in SQL).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The last step was ‘adding a bit of syntactic sugar’, which transformed this long chain of method calls into SQL-like syntax. It also illustrated why the ‘select’ clause is at the end of the LINQ expression, as opposed to the beginning as in SQL. The select clause simply filters the fields to be included in the anonymous type collection returned by the expression, though the first thing that needs to be defined is the data source. This is specified in the ‘from’ clause.&lt;br /&gt;&lt;br /&gt;One final note: LINQ can be implemented over anything that implements &lt;span style="font-family:courier new;"&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/span&gt;, though in situations where a small subset of the data is returned, the performance can be rather inefficient. To improve performance, objects would have to implement the &lt;span style="font-family:courier new;"&gt;IQueryable&amp;lt;T&amp;gt;&lt;/span&gt; interface. This basically allows the filter to be applied first before ‘hydrating’ the selected records into memory, instead of retrieving all records before filtering them.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;CON206 – Custom Activities in Windows Workflow Foundation&lt;/h4&gt;This was the last session on Day 1, so naturally one would be feeling tired after all the earlier sessions. Keeping this in mind, it was helpful that the presenter, &lt;a href="http://blogs.msdn.com/mwinkle/"&gt;Matthew Winkler&lt;/a&gt;, exhibited such energy and enthusiasm in his presentation that there was little chance of falling asleep!&lt;br /&gt;&lt;br /&gt;The session itself covered so much, from the &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/01/WindowsWorkflowFoundation/"&gt;basics of workflows&lt;/a&gt; to using workflows in multithreaded applications, that it was a fast-paced sprint through all the concepts with demos thrown in. I really appreciate how Matthew maintained a consistent pace so that nothing was skipped out, nor did the session go overtime. Of course, it does take a bit of time for these concepts to sink in, so it was great that the slides have been made available on the website.&lt;br /&gt;&lt;br /&gt;In simplest terms, a workflow is a set of activities in some arrangement, such as a state chart or basic flow diagram. The activities are the fundamental unit of work and may be composited into higher-level activities. Each activity has an associated execution state, which follows the state machine shown below:&lt;br /&gt;&lt;p style="text-align: center;"&gt;&lt;img style="border: 0px solid black" src="http://2.bp.blogspot.com/_PtRfH0rESBo/RuJh4vtTqqI/AAAAAAAAAAU/kZ_Xj978Zgw/s400/WorflowActivityStates.png" alt="Workflow activity states" id="BLOGGER_PHOTO_ID_5107752554898631330" /&gt;&lt;/p&gt;In this diagram, the green arrows represent transitions initiated by the workflow runtime, and all other arrows represent transitions initiated by the activity. Blue arrows represent final transitions, and red arrows represent faults triggered from within the activity.&lt;br /&gt;&lt;br /&gt;In practical terms, all activities inherit from &lt;span style="font-family:courier new;"&gt;System.Workflow.ComponentModel.Activity&lt;/span&gt; and therefore must implement the following virtual methods (note the American spelling):&lt;br /&gt;&lt;ul style="font-family: courier new;"&gt;&lt;li&gt;void Initialize(IServiceProvider provider)&lt;/li&gt;&lt;li&gt;ActivityExecutionStatus Execute(ActivityExecutionContext context)&lt;/li&gt;&lt;li&gt;ActivityExecutionStatus HandleFault(ActivityExecutionContext context)&lt;/li&gt;&lt;li&gt;ActivityExecutionStatus Cancel(ActivityExecutionContext context)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Additionally, an activity may implement the &lt;span style="font-family:courier new;"&gt;ICompensatable&lt;/span&gt; interface to 'compensate' activities that have finished and succeeded. Thus, in order to be compensated, an activity must be in the Closed state and have an ExecutionResult of "Succeeded". Probably an easy way to understand compensation of activities is to think of rolling back transactions when an operation has already completed, but some business requirement has not been met. When this happens, an exception is typically thrown and the runtime invokes the compensation handler of the activity. This means that the activity must also implement the following method:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:courier new;"&gt;ActivityExecutionStatus Compensate (ActivityExecutionContext context)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;I have to admit that I haven't actually played with Workflow Foundation yet, so there's obviously much more implementation detail in terms of putting everything together. The best place to start is with the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms742132.aspx"&gt;samples&lt;/a&gt;, though it's good to have that essential high-level knowledge in order to understand &lt;span style="font-style: italic;"&gt;why&lt;/span&gt; things are done the way they are.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Final thoughts&lt;/h4&gt;So Tech-Ed has well and truly finished for another year. It has been a great experience for me, and I learned quite a lot of useful information from it. I have to admit it has been hard to pass this knowledge on - especially when having to summarise parts of it in ten seconds or thereabouts and somehow convey it to a mass audience (i.e. my work colleagues). I could simply direct them to this blog for reference, but it looks like I'd need to deliver the knowledge in a mentoring session to be effective. Hopefully some of my colleagues are already reading this and getting something out of it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-5292241271101557319?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/5292241271101557319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=5292241271101557319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/5292241271101557319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/5292241271101557319'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/09/reflections-on-tech-ed-2007-part-5.html' title='Reflections on Tech-Ed 2007 - Part 5'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PtRfH0rESBo/RuJh4vtTqqI/AAAAAAAAAAU/kZ_Xj978Zgw/s72-c/WorflowActivityStates.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-7342156877086669017</id><published>2007-09-02T15:12:00.000+12:00</published><updated>2007-09-02T15:47:17.200+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tech-Ed'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Test-Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns and Practices'/><title type='text'>Reflections on Tech-Ed 2007 - Part 4</title><content type='html'>The previous posts in the series have covered highlights of the Tech-Ed sessions. This post continues the series with the discussion of a more technical session:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ARC302 –TDD Meets MVP&lt;/h4&gt;&lt;a href="http://blogs.msdn.com/rjacobs/"&gt;Ron Jacobs&lt;/a&gt; had entertained us as MC for the keynote presentation, so it was interesting to attend a session to find him in more of a university lecturer role providing valuable information and insight. As the last session I attended in the conference, it was interesting, stimulating and a superb finish to the whole event. A bit of a discalimer: the full title of his presentation also mentioned UX, but there was little coverage in this area apart from highlighting that there is no such thing as 'no design' - there is only good design and bad design.&lt;br /&gt;&lt;br /&gt;The main focus of this presentation was to convey how the MVP pattern can be adjusted to easily support &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test-Driven Development&lt;/a&gt; (TDD), a fairly recent concept. This session started with a few key points of TDD:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TDD is mainly about design, rather than testing&lt;/span&gt;. The tests that are written form the specification of what the software should do, therefore running the tests provides confirmation that the software not only works as expected, but also meets the functional requirements.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Tests should be written before code&lt;/span&gt;. Since the tests form the specification, it is logical for them to be written first. It doesn't make sense for the implementation to be done before the specification, and the specification to be confirmed afterwards - that would simply be a waste of effort. From personal experience on a project where the specification was updated after the implementation, this tactic carries a lot if risk and doesn't look professional.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TDD aids design&lt;/span&gt;. By writing tests upfront, a clearer picture emerges of what the class should actually do. This defines what class members are needed, since the tests hook into these directly. It also means that no more functionality is built in than is necessary. If it isn't within the code coverage of the tests, it isn't needed.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Refactoring is encouraged&lt;/span&gt;. The cycle of TDD is "Write test, write code, refactor". Refactoring is where duplication of effort is avoided and the code becomes streamlined as the need arises. It is also faster to make such steady progress towards a versatile implementation, than to try and do this upfront where one would sit and think. And think. And think some more. Then actually do something.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Now that TDD was understood, the meat of the session began. A brief history of architecture started, leading from monolithic applications to loose coupling with &lt;a href="http://heim.ifi.uio.no/%7Etrygver/themes/mvc/mvc-index.html"&gt;MVC&lt;/a&gt;, then to &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/08/DesignPatterns/"&gt;MVP&lt;/a&gt; (and its variants, &lt;a href="http://www.martinfowler.com/eaaDev/SupervisingPresenter.html"&gt;Supervising Controller&lt;/a&gt; and &lt;a href="http://www.martinfowler.com/eaaDev/PassiveScreen.html"&gt;Passive View&lt;/a&gt;). This led to the variant covered in the session, known as &lt;a href="http://atomicobject.com/pages/Presenter+First"&gt;Presenter-First&lt;/a&gt;. (A 376kB PDF version of a conference paper on this can be found &lt;a href="http://atomicobject.com/files/PresenterFirstAgile2006.pdf"&gt;here&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;In Presenter First, there is no direct interaction between the model and view – everything passes through the presenter. This is unlike standard MVP, where it is possible for notifications to be sent directly from the model to the view. The model and view are each encapsulated behind an interface, which forms a ‘contract’ used by the presenter. As a result, the model and view do not know anything about the presenter or each other.&lt;br /&gt;&lt;br /&gt;Since communication from the model and view back to the presenter is via notifications (e.g. events), no public methods are required on the presenter. Instead, the presenter subscribes to the view and model’s events in its constructor, which accepts the model and view interfaces as parameters. This means that the event handlers each correspond to commands to act on, and therefore implement the corresponding interaction logic: ‘When [particular event happens], do [this action]’. Having personally tried this on one of my personal projects, I can say that this is very helpful for breaking down the complexity of the presentation / interaction logic (which is separate from the &lt;a href="http://en.wikipedia.org/wiki/Domain_model"&gt;domain&lt;/a&gt; logic that is technically part of the model). This prevents the view from ‘getting too smart’ and therefore remains simple by:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Updating the display upon instruction by the presenter&lt;/li&gt;&lt;li&gt;Issuing commands to the presenter based on user input or other events (e.g. timers)&lt;/li&gt;&lt;/ul&gt;Here’s the process for breaking down the complexity with Presenter-First into easily manageable chunks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Establish the use cases&lt;/span&gt; / user stories of the application.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Define the commands for the presenter to act on&lt;/span&gt; based on breaking down the use cases into steps (i.e. When X happens, do Y). This also allows the model and view interfaces to be defined.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Flesh out the presenter&lt;/span&gt;, thus wiring the event handlers / commands to actions.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Develop the model&lt;/span&gt; and use the interface defined to link to the presenter.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Create the views&lt;/span&gt; using the interface defined. This basically involves mapping control event handlers to the notifications handled by the presenter, and wiring the interface methods to produce the output.&lt;/li&gt;&lt;/ul&gt;Of course, this may be done in an agile fashion in response to changing requirements. The model, view and presenter may also be developed in parallel.&lt;br /&gt;&lt;br /&gt;A good thing about this presentation is that it also clarified the role of particularly the model and presenter. The presenter is called the presenter for a reason – to present the state of the model to the view and to act on commands issued by the view. It is not simply the holding bin where all the logic (domain and interaction / presentation) is kept. Likewise, the model isn’t just for persisting data to memory, files or databases; it is responsible for enforcing data integrity, applying domain logic and processing data. Therefore in the analysis and design of the application, it is important to distinguish between the domain logic from the interaction logic so that the interaction between the model and presenter is kept as simple as possible. Likewise, care has to be taken to avoid placing interaction logic in the view. Most complexity within the view should be devoted to defining how to transform the data provided by the presenter into the visual representation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-7342156877086669017?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/7342156877086669017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=7342156877086669017' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7342156877086669017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7342156877086669017'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/09/reflections-on-tech-ed-2007-part-4.html' title='Reflections on Tech-Ed 2007 - Part 4'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3479177445190801715</id><published>2007-08-27T19:56:00.000+12:00</published><updated>2007-08-27T20:26:02.921+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Tech-Ed'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>Reflections on Tech-Ed 2007 - Part 3</title><content type='html'>In the previous post I listed what I found to be highlights out of the sessions I attended. This post continues the discussion of these session highlights.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;DEV309 – Best Practices for Team-based Development&lt;/h4&gt;This session, presented by &lt;a href="http://blog.svoboda.co.nz/"&gt;Lukas Svoboda&lt;/a&gt;, reminded me of &lt;a href="http://stevemcconnell.com/"&gt;Steve McConnell’s&lt;/a&gt; “&lt;a href="http://www.amazon.com/Rapid-Development-Steve-McConnell/dp/1556159005"&gt;Rapid Development&lt;/a&gt;” in its presentation of ‘&lt;a href="http://blogs.construx.com/blogs/stevemcc/archive/2007/06/15/Classic-Mistakes-Updated.aspx"&gt;classic mistakes&lt;/a&gt;’ that jeopardise the success of a team or project, as well as the signs that point toward success. Many of these may seem obvious, at least subconsciously, but there was value in seeing these items formalised and in reconfirming what may have been said / experienced before.&lt;br /&gt;&lt;br /&gt;These items can be used to form a checklist that would be used to assess how well a project is going:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is there adequate direction? Is the vision of this project well-defined?&lt;/li&gt;&lt;li&gt;Are deadlines and estimates fair and realistic?&lt;/li&gt;&lt;li&gt;Are the defined requirements clear and logical?&lt;/li&gt;&lt;li&gt;Are the defined requirements correct according to the vision of the project?&lt;/li&gt;&lt;li&gt;Is there adequate customer involvement and feedback?&lt;/li&gt;&lt;li&gt;Does every team member understand the value of each task?&lt;/li&gt;&lt;li&gt;Does the quality of the deliverables meet or exceed expectations?&lt;/li&gt;&lt;li&gt;Are team members able to carry out their work at a comfortable pace without being unnecessarily slowed down?&lt;/li&gt;&lt;li&gt;Are risks mitigated effectively?&lt;/li&gt;&lt;li&gt;Are problems dealt with effectively and efficiently?&lt;/li&gt;&lt;li&gt;Do team members feel a sense of responsibility and pride for their work?&lt;/li&gt;&lt;li&gt;Are team members comfortable working with each other, and free from personality conflicts?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;As an aside, it’s good to know that even though “Rapid Development” is 11 years old, it is still relevant today. The obvious advancements not mentioned in 1996 include &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; (as opposed to daily / weekly builds) and &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test-Driven Development&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In this session there was also quite a discussion of related concepts that extended beyond “Rapid Development”. A major theme was organisation of information – and how the lack of it can lead to ‘collaboration chaos’ where information is scattered across e-mail, instant messaging, meetings, phone calls, scrap paper and web pages (e.g. wikis). Lukas illustrated how the degree to which information is organised and processes are standardised influences the level of maturity of the team. It became clear that the lack of such organisation leads to a high degree of risk and waste, and can lead to miscommunication.&lt;br /&gt;&lt;br /&gt;Lukas also presented a good analogy to help explain why it can be so difficult to deliver the right product on time – as formulating a recipe. Just like in cooking, successful projects have a recipe for achieving the set goals. The thing is that this recipe has to be continually tested and evolved in order to improve the outcome. On new projects, there is also skill required in selecting the right ‘ingredients’ as appropriate for the team and project. One size does not fit all. The ingredients used to make a steamed pudding aren't the same ingredients used for nachos.&lt;br /&gt;&lt;br /&gt;Apart from picking methodologies as ingredients, much difficulty in delivering the right product on time can also arise from human factors. There is often inertia to change, possibly out of fear for the unknown. However the degree of this inertia can be significantly reduced if the changes are small and made often – just like in &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;agile&lt;/a&gt; (as opposed to ‘big-bang’) development.&lt;br /&gt;&lt;br /&gt;The recommendation from the Interface Design Patterns session of being multi-disciplinary also applies in the day-to-day running of a project. It was good to see the points of view of the different roles (developers, testers, analysts, etc.) in a software project summarised as points on a slide, relating to their respective areas of concern and responsibilities within a project. It is important to have this understanding of how the others think, so that team members can make each other's jobs easier. Just because one member is a developer, for instance, doesn't mean that this person is stuck doing only development tasks and therefore can't assist with or give value-added input for analysis, testing or design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3479177445190801715?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3479177445190801715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3479177445190801715' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3479177445190801715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3479177445190801715'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/08/reflections-on-tech-ed-2007-part-3.html' title='Reflections on Tech-Ed 2007 - Part 3'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-1823211865354352940</id><published>2007-08-26T11:27:00.000+12:00</published><updated>2007-08-26T11:54:32.154+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Usability'/><category scheme='http://www.blogger.com/atom/ns#' term='Tech-Ed'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Reflections on Tech-Ed 2007 - Part 2</title><content type='html'>There was obviously more to Tech-Ed than the excellent keynote mentioned in the previous post. As I stated earlier, the sessions made up bulk of the conference, and there were some definite highlights among the sessions I attended. Here are the highlights, ordered from the high-level to the technical:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ARC306 – Interface Design Patterns&lt;/li&gt;&lt;li&gt;DEV309 – Best Practices for Team-based Development&lt;/li&gt;&lt;li&gt;ARC302 –TDD Meets MVP&lt;/li&gt;&lt;li&gt;DEV313 – LINQ Deep Dive&lt;/li&gt;&lt;li&gt;CON206 – Custom Activities in Windows Workflow Foundation&lt;/li&gt;&lt;/ul&gt;These sessions will be discussed in the remaining posts within this series, starting with ARC306 below. The presentation slides can be downloaded from the &lt;a href="http://www.microsoft.com/nz/teched07/downloads.aspx"&gt;Tech-Ed website&lt;/a&gt;, with the exception of DEV309 – which can be downloaded from &lt;a href="http://blog.svoboda.co.nz/2007/08/22/Presentation+From+TechEd+2007+DEV309++Best+Practices+For+Software+Development+Teams.aspx"&gt;Lukas Svoboda’s blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ARC306 – Interface Design Patterns&lt;/h4&gt;Following on from the theme of the keynote, this session provided numerous points to consider when designing and building applications. The central focus covered the cloud of related concepts such as interaction design, usability, human factors, HCI and UI engineering. The presenter, &lt;a href="http://www.flightless-kiwi.com/blog/default.aspx"&gt;Darryl Chantry&lt;/a&gt;, delivered an engaging and entertaining presentation on these topics, punctuated with interesting videos of these concepts in action.&lt;br /&gt;&lt;br /&gt;Here are some key points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Be multi-disciplinary&lt;/span&gt;. By developing a wider skill set (beyond the mechanics of programming software), software developers can more effectively convey information and therefore satisfy the needs of users better. Darryl displayed a diagram to demonstrate this – a full-colour artistic rendering of a cross-section of the human head, depicting an aneurysm. The extraordinary thing is that this was hand-drawn by a neurosurgeon. Not only did this neurosurgeon have the medical skills and knowledge to understand aneurysms, he/she also had the artistic skills to render this in a way that effectively communicates this specialist medical knowledge to anyone outside their profession.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Good design is invisible&lt;/span&gt;. By human nature, people take things for granted when they work as expected, but actively notice or complain if something is wrong. Therefore a good way to assess how good a design is, is to ask ‘What could cripple usability?’ ‘What’s slowing me down [as a user]?’ Design can be improved by removing these obstacles, but it takes skill to identify these obstacles in the first place.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Users want to be in control&lt;/span&gt;. If software does things that are unexpected, users won’t trust it. Their expectations are based on what is familiar to them and fits a particular pattern. This also presents a paradox: that software can be designed to be so simple to use that it’s revolutionary, yet by its revolutionary nature it becomes unfamiliar for users (e.g. if the standard control types aren’t used).&lt;/li&gt;&lt;/ul&gt;Just as interfaces in C# or Java provide a contract between a caller and a class that implements the interface, the user interface provides a contract between the software and the user. When using the software, the UI declares, “Under these circumstances, this is what I’ll do,” to the user, who interacts based on the contract. If clicking a certain button causes some extra things to happen that are behind the user’s back (let alone unexpected), or leaves out another action, then that contract is broken and so is the user’s trust.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-1823211865354352940?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/1823211865354352940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=1823211865354352940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1823211865354352940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/1823211865354352940'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/08/reflections-on-tech-ed-2007-part-2.html' title='Reflections on Tech-Ed 2007 - Part 2'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-3438411758258772516</id><published>2007-08-21T08:53:00.000+12:00</published><updated>2007-08-26T11:52:34.332+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Tech-Ed'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><title type='text'>Reflections on Tech-Ed 2007 - Part 1</title><content type='html'>Last week I was at the &lt;a href="http://www.microsoft.com/nz/teched/"&gt;Tech-Ed 2007&lt;/a&gt; conference, held in Auckland at the SkyCity Convention Centre. It was a great opportunity to be there attending the sessions, exploring the Marketplace and supervising the Hands-On Labs. For those who don't know, Tech-Ed is a conference organised by Microsoft and sponsored by a host of IT and Systems-related organsiations. The bulk of the conference is devoted to the sessions covering not only Microsoft tools and technologies, but also software development concepts and practices. These sessions are complemented by the hands-on labs, where conference delegates have the opportunity to try out the various technologies. Then there's the Marketplace, which is basically an expo with promotional freebies and prize draws on the side; and of course, the TechFest party on the second night, featuring live entertainment including &lt;a href="http://www.evermoreband.com/news/"&gt;Evermore&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This year's theme was "Make your mark" - which basically revolved around User Experience (UX). This theme was superbly introduced in the keynote presentation by Lou Carbone of &lt;a href="http://www.expeng.com/who.htm"&gt;Experience Engineering Inc.&lt;/a&gt; and was highlighted in a few of the subsequent sessions throughout the conference. Even though this presentation wasn't directly related to the mechanics of software development, it contained some important points that transfer directly to the higher-level aspects of building software - particularly concerning the fulfilment of user needs and desires.&lt;br /&gt;&lt;br /&gt;Firstly, it is worth noting that in general terms, user experience refers to all factors that impact a customer's emotions, attitudes and behaviours, for the entire purchase process from identifying the need to using the product or service. Or as Wikipedia puts it, &lt;a href="http://en.wikipedia.org/wiki/User_experience"&gt;user experience&lt;/a&gt; is "the overall experience and satisfaction a user has when using a product or system" When applied to software, most of the user experience is determined through the prospecting, acquisition, installation and use of the software. That's where the interaction design, functionality, aesthetics and other human factors play their part.&lt;br /&gt;&lt;br /&gt;Here are some of the main points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;User Experience is closely tied to the combination of a customer's emotions, attitudes and behaviours&lt;/span&gt;. Based on a customer's experience, they're going to feel particular emotions (either consciously or subconsciously), adopt certain attitudes such as trust or loyalty, and apply certain behaviours. These behaviours can range from doing repeat business and recommending your brand and software to others, to demanding refunds and spreading the bad word. Basically user experience will determine whether people use your software or not.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Business has changed from "Make &amp; Sell" to "Sense &amp;amp; Respond"&lt;/span&gt;. Think from a customer's point of view - if you have identified a need for something, you'll make a list of criteria (at least subconsciously) that this something will have to meet in order for you to consider buying it. Considering that the given market is likely to have competition, you'd go for the one that meets your criteria the best. The software of someone who made it assuming that people will naturally want to buy it is less likely to be chosen than the software made by someone who made an effort in sensing what people actually wanted. It is this understanding of the fundamental needs that will allow extra value to be created,&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;User satisfaction does not guarantee loyalty&lt;/span&gt;. Carbone illustrated this through results from a survey, which found that of those who defected to another provider of products &amp; services, 60-80% had indicated that they were at least satisfied with the products &amp;amp; services prior to defection. It is likely that these people found a better provider who delivered a superior experience. And what indicates 'satisfied'? Carbone indicated that on a scale of 0-10, 7/10 and above indicates pretty good satisfaction, while anything below was 'average' or 'poor'. So the new competitive advantage is therefore to create the most satisfying user experience.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Create value, don't extract it. Profit is the reward, not a target&lt;/span&gt;. This is fairly self-explanatory, though it indicates a change of mindset. Carbone illustrated a once-popular restaurant franchise in the US, which focussed on maintaining profits, took cost-cutting measures (e.g. downgrading paper serviettes to single-ply) and eventually went under.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Pay attention to experience clues.&lt;/span&gt; These are subtle details that have a subconscious effect on customers' attitudes and emotions. When checking into a hotel, you'd expect to find the bathroom spotlessly clean. Finding clues that indicate the previous guest's presence would have a negative impact. Just like installing software and finding that the interface controls are displayed crooked.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;As software developers, it can be hard to see how these high-level business and marketing concepts apply to creating software, but it is worth being aware of them. For commercial development this is obvious - creating value and good user experiences brings in business that allows developers to be paid, and also enhances the business' / developer's reputation. In open-source projects, creating value makes the software more desirable and entices greater uptake - possibly converting customers from commercial vendors. As for personal projects, you're more likely to use your own software rather than tinker with it endlessly or give up on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-3438411758258772516?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/3438411758258772516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=3438411758258772516' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3438411758258772516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/3438411758258772516'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/08/reflections-on-tech-ed-2007-part-1.html' title='Reflections on Tech-Ed 2007 - Part 1'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1801443688792449833.post-7688494792427837385</id><published>2007-07-07T14:53:00.000+12:00</published><updated>2007-07-07T15:39:34.343+12:00</updated><title type='text'>First Post</title><content type='html'>After quite a bit of encouragement by peers at work, I've finally decided to start up a blog, so here it is. This will include a variety of items ranging from technical tidbits (mainly relating to software development - which I do for a living) to things related to the arts, especially music.&lt;br /&gt;&lt;br /&gt;Basically, the items will cover learnings discovered through my work at &lt;a href="http://www.intergen.co.nz/"&gt;Intergen&lt;/a&gt;, things relating to my hobbies and anything that else that captures my interest, so don't be surprised if you also see photos or graphics created in &lt;a href="http://www.blender.org/"&gt;Blender&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Feel free to post comments. It'll be quite interesting to see how this all takes off...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1801443688792449833-7688494792427837385?l=tech-and-arts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tech-and-arts.blogspot.com/feeds/7688494792427837385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1801443688792449833&amp;postID=7688494792427837385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7688494792427837385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1801443688792449833/posts/default/7688494792427837385'/><link rel='alternate' type='text/html' href='http://tech-and-arts.blogspot.com/2007/07/first-post.html' title='First Post'/><author><name>Daniel McGaughran</name><uri>http://www.blogger.com/profile/10872686544518245197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
