﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>igloocoder.com</title><link>http://www.igloocoder.com/</link><description>igloocoder.com</description><copyright>igloocoder.com Consulting Inc. (c) 2013</copyright><ttl>60</ttl><item><title>UI Workflow is business logic</title><description>&lt;p&gt;Over my years as a programmer I’ve focussed a lot of attention and energy on business logic.  I’m sure you have too.  Business logic is, after all, a huge part of what our clients/end users want to see as an output from our development efforts.  But what is included in business logic?  Usually we think of all the conditionals, looping, data mangle-ment, reporting and other similar things.  In my past experiences I’ve poured immense effort into ensuring that this business logic was correct (automated and manual testing), documented (ubiquitous language, automated testing and, yes, comments when appropriate) and centralized (DDD).  While I’ve had intense focus on these needs and practices, I’ve usually neglected to recognize the business logic that is buried in the UI workflow within the application.&lt;/p&gt;  &lt;p&gt;On my current project I’ve been presented with an opportunity to explore this area a bit more in depth.  We don’t have the volume of what I have traditionally considered business logic.  Instead the application is very UI intensive.  As a result I’ve been spending a lot more time worrying about things like “What happens when the user clicks XYZ?”  It became obvious to us very early on that this was the heart of our application’s business logic.&lt;/p&gt;  &lt;p&gt;Once I realized this we were able to focus our attention on the correctness, discoverability, centralization and documentation of the UI workflow.  How did we accomplish this then?  I remember reading somewhere (written by Jeremy Miller I think, although I can’t find a link now) the assertion that “Every application will require the command pattern at some point.” I did some research and found a &lt;a href="http://www.lostechies.com/blogs/derickbailey/archive/2009/12/22/understanding-the-application-controller-through-object-messaging-patterns.aspx"&gt;post by Derick Bailey&lt;/a&gt; explaining how he was using an Application Controller to handle both an Event Aggregator and workflow services.  To quote him:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Workflow services are the 1,000 foot view of how things get done. They are the direct modeling of a flowchart diagram in code.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I focused on the first part of his assertion and applied it to the flow of user interfaces.  Basically it has amounted to each user workflow (or sequence of UI concepts) being defined, and executed, in one location.  As an example we have a CreateNewCustomerWorkflowCommand that is executed when the user clicks on the File | Create Customer menu.  It might look something like this:&lt;/p&gt;  &lt;p /&gt;  &lt;div style="width: 850px; color: black; overflow: auto"&gt;   &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;CreateNewCustomerWorkflowCommand&lt;/span&gt;&lt;span style="color: #000000"&gt;  : &lt;span style="color: #2b91af"&gt;ICommand&lt;/span&gt;&lt;span style="color: #000000"&gt; &amp;lt;&lt;span style="color: #2b91af"&gt;CreateNewCustomerWorkflow&lt;/span&gt;&lt;span style="color: #000000"&gt; &amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;2:&lt;/span&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;ISaveChangesPresenter&lt;/span&gt;&lt;span style="color: #000000"&gt;  _saveChangesPresenter;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;ICustomerService&lt;/span&gt;&lt;span style="color: #000000"&gt;  _customerService;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;ICreateNewCustomerPresenter&lt;/span&gt;&lt;span style="color: #000000"&gt;  _createNewCustomerPresenter;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;6:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  CreateNewCustomerWorkflowCommand(&lt;span style="color: #2b91af"&gt;ISaveChangesPresenter&lt;/span&gt;&lt;span style="color: #000000"&gt;  saveChangesPresenter,&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;8:&lt;/span&gt;                                             &lt;span style="color: #2b91af"&gt;ICustomerService&lt;/span&gt;&lt;span style="color: #000000"&gt;  customerService,&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;9:&lt;/span&gt;                                             &lt;span style="color: #2b91af"&gt;ICreateNewCustomerPresenter&lt;/span&gt;&lt;span style="color: #000000"&gt;  createNewCustomerPresenter)&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;10:&lt;/span&gt;     &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;11:&lt;/span&gt;         _saveChangesPresenter = saveChangesPresenter;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;12:&lt;/span&gt;         _customerService = customerService;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;13:&lt;/span&gt;         _createNewCustomerPresenter = createNewCustomerPresenter;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;14:&lt;/span&gt;     &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;15:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;16:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  Execute(&lt;span style="color: #2b91af"&gt;CreateNewCustomerWorkflow&lt;/span&gt;&lt;span style="color: #000000"&gt;  commandParameter)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;17:&lt;/span&gt;     &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;18:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;  (commandParameter.CurrentScreenIsDirty)&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;19:&lt;/span&gt;         &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;20:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;var&lt;/span&gt;&lt;span style="color: #000000"&gt;  saveChangesResults = _saveChangesPresenter.Run();&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;21:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;  (saveChangesResults.ResultState == &lt;span style="color: #2b91af"&gt;ResultState&lt;/span&gt;&lt;span style="color: #000000"&gt; .Cancelled) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt; ;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;22:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;  (saveChangesResults.ResultState == &lt;span style="color: #2b91af"&gt;ResultState&lt;/span&gt;&lt;span style="color: #000000"&gt; .Yes)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;23:&lt;/span&gt;             &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;24:&lt;/span&gt;                 _customerService.Save(commandParameter.CurrentScreenCustomerSaveDto);&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;25:&lt;/span&gt;             &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;26:&lt;/span&gt;         &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;27:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;28:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;var&lt;/span&gt;&lt;span style="color: #000000"&gt;  newCustomerResults = _createNewCustomerPresenter.Run();&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;29:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;  (newCustomerResults.ResultState == &lt;span style="color: #2b91af"&gt;ResultState&lt;/span&gt;&lt;span style="color: #000000"&gt; .Cancelled) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt; ;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;30:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;  (newCustomerResults.ResultState == &lt;span style="color: #2b91af"&gt;ResultState&lt;/span&gt;&lt;span style="color: #000000"&gt; .Save)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;31:&lt;/span&gt;         &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;32:&lt;/span&gt;             _customerService.Save(newCustomerResults.Data);&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;33:&lt;/span&gt;         &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;34:&lt;/span&gt;     &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;35:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p /&gt;

&lt;p&gt;As you can see the high level design of the user interaction, and service interaction, is clearly defined here.  Make no mistake, this is business logic.  It answers the question of how does the business expect the creation of a new customer to occur.  We’ve clearly defined this situation in one encapsulated piece of code.  By doing this we have now laid out a pattern whereby any developer looking for a business action can look through these workflows.  They clearly document the expected behaviour during the situation.  Since we’re using Dependency Injection in our situation, we can also write clear tests to continuously validate these expected behaviours.  Those tests, when done in specific ways, can also enhance the documentation surrounding the system.  For example, using BDD style naming and a small utility to retrieve and format the TestFixture and Test names we can generate something like the following:&lt;/p&gt;

&lt;p /&gt;

&lt;div style="width: 850px; color: black; overflow: auto"&gt;
  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_current_screen_has_pending_changes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;2:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_user_should_be_prompted_with_the_option_to_save_those_changes()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;4:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;5:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_user_chooses_to_cancel_when_asked_to_save_pending_changes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;7:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_pending_changes_should_not_be_saved()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_create_new_customer_dialog_should_not_be_displayed()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;10:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;11:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;12:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_user_chooses_not_to_save_pending_changes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;13:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;14:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_pending_changes_should_not_be_saved()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;15:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_create_new_customer_dialog_should_be_displayed()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;16:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;17:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;18:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_user_chooses_to_to_save_pending_changes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;19:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;20:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_pending_changes_should_be_saved()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;21:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_create_new_customer_dialog_should_be_displayed()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;22:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;23:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;24:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_user_chooses_to_cancel_from_creating_a_new_customer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;25:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;26:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_new_customer_should_not_be_saved()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;27:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;28:&lt;/span&gt; &lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;29:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #2b91af"&gt;When_the_user_chooses_to_create_a_new_customer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;30:&lt;/span&gt; &lt;span style="color: #000000"&gt; &lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em; background: #f4f4f4"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;31:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt;&lt;span style="color: #000000"&gt;  &lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;  the_new_customer_should_be_saved()&lt;span style="color: #000000"&gt;{&lt;/span&gt;&lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="margin: 0em"&gt;&lt;span style="text-align: right; width: 30px; display: inline-block; color: black; margin-right: 10px"&gt;32:&lt;/span&gt; &lt;span style="color: #000000"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p /&gt;

&lt;p&gt;As you can see, this technique allows us to create a rich set of documentation outlining how the application should interact with the user when they are creating a new customer.&lt;/p&gt;

&lt;p&gt;Now that we’ve finished implementing this pattern a few times, have I seen any drawbacks?  Not really.  If we didn’t use this technique we’d still have to write the code to coordinate the screen sequencing.  That sequencing would be spread all over the codebase, most likely in the event handlers for buttons on forms (or their associated Presenter/Controller code).  Instead we’ve introduced a couple more classes per workflow and have centralized the sequencing in them.  So the trade off was the addition of a couple of classes per workflow for more discoverability, testability and documentation.  A no brainer if you ask me.&lt;/p&gt;

&lt;p&gt;Is this solution the panacea?  Absolutely not.  It works very well for the application that we’re building though.  In the future will I consider using this pattern? Without doubt.  It might morph and change a bit based on the next application’s needs, but I think that the basic idea is strong and has significant benefits.&lt;/p&gt;

&lt;p&gt;A big shout out to Derick Bailey for writing a great post on the &lt;a href="http://www.lostechies.com/blogs/derickbailey/archive/2009/12/22/understanding-the-application-controller-through-object-messaging-patterns.aspx"&gt;Application Controller, Event Aggregator and Workflow Services&lt;/a&gt;.  Derick even has a sample app available for reference.  I found it to be great for getting started, but it is a little bit trivial as it only implements one simple workflow.  Equally big kudos to Jeremy Miller and his &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/07/25/the-build-your-own-cab-series-table-of-contents.aspx"&gt;Build Your Own CAB&lt;/a&gt; series which touches all around this type of concept.  Reading both of these sources helped to cement that there was a better way.&lt;/p&gt;</description><link>http://www.igloocoder.com/2303/ui-workflow-is-business-logic?key=b50486d2-a516-4f06-b33b-e4f04a8ea5c2</link><guid>http://www.igloocoder.com/2303/ui-workflow-is-business-logic?key=b50486d2-a516-4f06-b33b-e4f04a8ea5c2</guid><pubDate>Sun, 26 Sep 2010 21:42:00 GMT</pubDate></item><item><title>Rotating text using Graphics.DrawString</title><description>&lt;p&gt;Recently I needed to create a custom WinForms label-like control that allowed for the text to be displayed in a rotated fashion.  Our needs were only for four rotation locations; 0 degrees (the default label position), 90, 180 and 270 degrees.  There were other complicating factors, but for this post we’ll only concentrate on this component of the control.&lt;/p&gt;

&lt;p&gt;To rotate text using the Graphics.DrawString method you only have to do a couple of things.  First you have to use the Graphics.TranslateTransform method, then the Graphics.RotateTransform method, and followed by the Graphics.DrawString.  Here’s what it looks like.&lt;/p&gt;

&lt;p&gt;using (var brush = new SolidBrush(ForeColor)) 
  &lt;br /&gt;{ 

  &lt;br /&gt;    var stringFormat = new StringFormat 

  &lt;br /&gt;                       { 

  &lt;br /&gt;                           Alignment = StringAlignment.Near, 

  &lt;br /&gt;                           LineAlignment = StringAlignment.Near 

  &lt;br /&gt;                       }; 

  &lt;br /&gt;    e.Graphics.TranslateTransform(transformCoordinate.X, transformCoordinate.Y); 

  &lt;br /&gt;    e.Graphics.RotateTransform(rotationDegrees); 

  &lt;br /&gt;    e.Graphics.DrawString(Text, Font, brush, DisplayRectangle, stringFormat); 

  &lt;br /&gt;}&lt;/p&gt;

&lt;p&gt;What you see are the three steps that I outlined above.  Let’s start at the bottom and work our way up.  The code exists inside of a UserControl’s overridden OnPaint event.  The DrawString method makes use of some of the properties on the control, like Text and Font.  It also uses the DisplayRectangle property to set the boundaries for the drawing to be the same size as the control.  This is one of the keys to making the rotations work.  The other key is to provide the DrawString with the StringFormat settings.  By setting them to be StringAlignment.Near for both the Alignment and LineAlignment, you are declaring that the text’s location should be based in the top left of the DisplayRectangle’s area.&lt;/p&gt;

&lt;p&gt;Graphics.RotateTransform is how you set the rotation value.  In the case of our control, we would be putting in a value from the list of 0, 90, 180, and 270.  As you might expect the rotations are clockwise with 0 starting with the text in the ‘normal’ location.&lt;/p&gt;

&lt;p&gt;Graphics.TranslateTransform is where the last piece of magic occurs.  It is here that you set where the top right corner of the text drawing area will be located in the DisplayRectangle’s area.  Here are some images that will help clarify the situation.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.igloocoder.com/images/0degrees.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="0degrees" border="0" alt="0degrees" src="http://www.igloocoder.com/images/0degrees.png" width="240" height="210" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;When you need the text to appear the same as “Text Area” does in the above image (rotated 0 degrees), you need to set the TranslateTransform X and Y parameters to be those that are designated by the “X” in the image.  In this case, it’s X=0 and Y = 0.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.igloocoder.com/images/90degrees.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="90degrees" border="0" alt="90degrees" src="http://www.igloocoder.com/images/90degrees.png" width="240" height="211" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The picture above shows you what you should be displayed when you are rotating the text “Text Area” 90 degrees.  Again, you need to set the TranslateTransform, but this time the values are slightly different.  The Y parameter is still 0, but the X parameter equals the height of the text.  You can get this value by using the following line of code:&lt;/p&gt;

&lt;p&gt;var textSize = TextRenderer.MeasureText(Text, Font); 
  &lt;br /&gt;textSize.Height;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.igloocoder.com/images/180degrees.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="180degrees" border="0" alt="180degrees" src="http://www.igloocoder.com/images/180degrees.png" width="240" height="209" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To render the text upside down we set the rotation to 180 degrees and then, again, determine the location of the TranslateTransform X and Y coordinates.  Like we did for the last rotation, we will need to retrieve the text size to set these values.  For this situation Y will be the text height and X will be the text width.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.igloocoder.com/images/270degrees.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="270degrees" border="0" alt="270degrees" src="http://www.igloocoder.com/images/270degrees.png" width="240" height="208" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The final step is to make the rotation work for 270 degrees.  Like all the others, we need to set the X and Y coordinates for the TranslateTransform method call.  Here the Y value will be the text width and the X value will be 0.&lt;/p&gt;

&lt;p&gt;This is simply the first step of many to making a control that will allow rotation of the text and locating it in one of 9 locations in a 3x3 grid representation of the control’s DisplayRectangle.  More on that in another blog post though.&lt;/p&gt;</description><link>http://www.igloocoder.com/2298/rotating-text-using-graphics-drawstring?key=5f287567-1b4c-4f3c-be30-d180d10680a4</link><guid>http://www.igloocoder.com/2298/rotating-text-using-graphics-drawstring?key=5f287567-1b4c-4f3c-be30-d180d10680a4</guid><pubDate>Wed, 09 Jun 2010 10:06:17 GMT</pubDate></item></channel></rss>