Archive for February, 2008

MVC, and the *new* things that may not be considered *new* any longer

It’s always funny how people, at this day and age, still look at OOP and Design Patterns as some sort of "new thing that probably Microsoft created and is trying to shove down our throats", even though those are things that have been around for decades now, and still, a lot of people don’t really quite get it.

The "new" thing now seems to be the MVC (Model-View-Controller). I must confess the first time I heard about this pattern has been just a couple of years ago (like 3 or 4 maybe…). Last night, I stumbled across this article, where I’ve read the following:

Model-View-Controller

The MVC pattern was implemented as early as 1974 in the Smalltalk project. It has been given, over the years, many variations, such as Model-Interactor and Model-View-Presenter. Each of these implments the idea of ports-and-adapters on the primary ports, not the secondary ports.

1974?? That was two years before I was even born!!! Didn’t know it was that old.  🙂

The sad thing is that I’ve been thinking a lot about how to put together something along those lines to work in smart client apps, but it isn’t quite simple. MVC, MVP, Supervising Controller, Passive View, they’re all related but have subtle differences. they’re all, however, the total opposite of anything Visual Studio gives us out of the box, like I was mentioning the other day…

Advertisement

Leave a comment

Just finished reading Working Effectively with Legacy Code

Yesterday I’ve finally finished reading the following book:

Working Effectively with Legacy Code (Robert C. Martin Series)
by Michael Feathers

Read more about this title…

I had already heard great comments about it, and then over a month ago my buddy Lynn Evans told me I had to read it and let me borrow his copy. I’m glad I did.

I must say when I first saw the title of this book, I thought to myself: "hmm… it’s probably all about old C code, mainframe applications, etc. I don’t think I’d be interested in this book…". Boy, was I wrong…

Yes, there’s quite a bunch of sample code in languages I’m not particularly comfortable with, such as C++, Java, and C, but anybody used to C# or VB should be able to follow the examples without a problem (not that I wouldn’t like to see a C#-only version of this book, but that’s beyond the point…).

Even though some people, like myself, would read the "legacy" in the title and think that wouldn’t apply to code written as back as this morning, the author quickly explains what legacy code is: any code without test is legacy code.

According to the author, it doesn’t matter how badass the design and implementation of some code may be, or how killer the developer who wrote is; if there’s no tests for the code, it’s considered legacy code.

When I think of legacy code, I think of code that’s hard to maintain. It’s hard because I don’t know what impact any change I make to the code would have on the application. Since there are not tests, even a one-liner change can be dangerous; let alone some more major changes.

Even before the first chapter starts, I’ve already run across this gem:

Designs that cannot tolerate changing requirements are poor designs to begin with. It is the goal of every competent software developer to create designs that tolerate change.

The book covers many techniques for writing tests for code that hasn’t been written with tests in mind. It tackles typical questions such as "how do I test private methos? And should I?". It also presents considerations on removing dependencies so to be able to put the code under test, as we do that, we usually end up with code that’s easier to maintain and extend. All of this going through lots of refactoring techniques.

I’m glad to see that quite a few of the techniques I’ve figured out on my own are listed in this book, with samples that come from real world experiences.

Excellent book, recommended to any serious developer.

Leave a comment

State Machines and GUI interaction – Part II

This is the sequel for this post. In this installment I’m going to cover a simple scenario that I’m always running across: a simple data-entry form, and the synchronization of its buttons used to load, create, or save data. The sample form I’ll cover here is pretty simple, and it looks like this:

Form

That’s nothing more than a simple form to maintain Customer’s data. I’m just capturing the customer’s name, because the amount of data gathered here isn’t relevant to the exercise. The main thing I’m looking for here is the synchronization of the Load, New, and Save buttons. For instance, when the user clicks New, I want all the buttons to become disabled. As soon as the user makes any change to the data on the form, the Save button then becomes enabled. Then, when the user clicks on Save, both Load and New become enabled, whereas Save becomes disabled. Of course, there’s a lot more buttons we’d normally have in such form (such as Delete, Search, etc.), but that’s beyond the scope here.

The quick implementation would be to just go on the form and add some event handlers for the buttons, in which we’d enable/disable other controls accordingly. However, eventually we may want to move those buttons somewhere else (maybe put them a user control, as opposed to directly sitting on the form, or maybe put them in a toolbar or Ribbon control…). Also, we may want other ways to access the functionality (for instance, we may want to press Ctrl+N for New, and Control+S for Save…). The problem is that if all the logic is in the form, we’d have to put too much code in there so to handle buttons being somewhere, shortcuts, etc.

I decided to look at the form as it having different "states": for instance, a "viewing" state, which is the case when the user is viewing some data, and a "dirty" state, which is the case when the user has made changes to the data but hasn’t saved it yet.

Enter the State Machine

The following State Transition Table lists the simple states I’ve identified for my simple form:

Current State Event New State Action (transition)
Initial New New  
  Load Viewing  
New DataChanged Dirty TurnOnDirtyIndicator
Dirty Save Viewing TurnOffDirtyIndicator
Viewing New New  
  DataChanged Dirty TurnOnDirtyIndicator

Below is a State Diagram to present another view of the states:

diagram

Using the State Machine Toolkit (discussed in Part I), I’ve created a state machine to handle those states. I’ve named the machine DataInterfaceInteractionBase (the idea being that the machine handles the interactions in a "data" user interface…). My default concrete implementation of this machine is called DataInterfaceInteraction. fThe diagram below shows what these classes look like:

StateMachine

The DataInterfaceInteraction class implements the abstract methods (TurnOnDirtyIndicator and TurnOffDirtyIndicator), as well as it overrides a few of the virtual methods (EntryDirty, EntryInitial, EntryNew, EntryViewing). The methods delegate execution to an IDataInterfaceInteractionController, like so:

MethodsCallController

The diagram below shows the relationship between the state machine and the controller:

StateMachineController

Notice the following aspects of the IDataInterfaceInteractionController:

  • It has methods that match the ones on the state machine (such as EntryDirty, EntryNew, TurnOnDirtyIndicator, etc.);
  • The SetHost method is designed to take in a reference to the state machine that the controller handles;
  • The TurnOnDirtyIndicator and TurnOffDirtyIndicator methods raise the TurningOnDirtyIndicator and TurningOffDirtyIndicator events, respectively;
  • The RegisterInterfaceController method takes in "data interface controllers" and register them with the Interaction controller. Any number of interface controllers can be registered.

The constructor for that class looks like this:

Constructor

It takes in an interaction controller, as well as an array of data interface controllers, and then uses those references to register things accordingly.

This is what the IDataInterfaceController looks like:

DataInterfaceController 

The properties essentially dictate whether Load, New, and Save features should be enabled or not. The SetInteractionStateMachine method takes an instance of the the interaction state machine that this controller is associated with.

The DataInterfaceInteractionController class

Next, I’ve implemented my default DataInterfaceInteractionController class, which we attach to the interaction state machine. Let’s look at the diagram to see how things are related thus far:

Diagram2

Notice the class has a DataInterfaceControllers collection, which is a Collection of IDataInterfaceController implementers. Nothing too fancy there. The RegisterInterfaceController method is used for adding controllers to that collection:

Registercontroller

More importantly, the methods such as EntryViewing and EntryDirty (which get called when the state machine is entering those states), iterate through the data interface controllers and set the LoadEnabled, NewEnabled, and SaveEnabled properties accordingly:

EntryDirty

Notice, for instance, that when the user is "viewing" some data, both Load and New are enabled, while Save is disabled. When the user then makes changes to the data, causing a transition to the Dirty state, both Load and New become disabled, whereas Save becomes enabled. In the real world we’d probably have more complex implementations so to decide whether or not some features are enable or disabled (for instance, we may have security restrictions depending on the user, or any other sort of business rule).

At this point we’re only determining which "features" should be enabled or disabled depending on the current state we’re in. That means we’re only programming the behavior here. We don’t have any code at this level that is enabling or disabling buttons, keyboard shortcuts, or anything like that; we leave that up to the implementes of IDataIntefaceController, which will take a look at next.

Hooking up the CustomerEditForm to the Interaction state machine

The CustomerEditForm has an Interactions property, which stores a reference to the DataInterfaceInteractionBase class (which is the abstract baseclass for the interactions state machine):

PropertySM

Setting up the Data Interface Interaction Controller

Next, I’ve created a GetInteractionController method, which instantiates the interaction controller, and sets up event handlers for its TurningOffDirtyIndicator and TurningOnDirtyIndicator events:

GetController

The event handlers are just simple anonymous methods. All we’re doing there is to display a little asterisk (*) after the title in the form’s title bar whenever the data is  "dirty":

FormDirty

Sending events to the State Machine

It’s necessary to send events to the state machine, so that it can transition to the appropriate states. We’ll first use the buttons located on the customer edit form to send those events:

FormInteraction

Since I’ve based my state machine on a "passive" machine, anytime I send events to the machine (by calling the Send method and passing in the event id), I also have to call the Execute method. I created a simple helper method around these calls:

Helper

Next, I’ve hooked up event handlers for the Load, New, and Save buttons. Those handlers are very simple, since all they do is to send events to the state machine. I’d also handle any event that would warn me about the data being dirty (such as TextChanged events in this form…):

SendingSignals

The first Data Interface Controller

Remember that the Data Interface Controller is the object that enables and disables the features (new, load, save…) accessed by the interaction state machine. We can have as many data interface controllers as we need.

The first implementer for the IDataInterfaceInteractionController interface is the customer edit form itself, since it hosts the buttons that send events to the state machine. The implementation of the interface is as simple as this (one property for each feature):

NewEnabled

Nothing to exciting, right? Just some interaction with the Enabled property on the specific buttons.

I’ve then created an InitializeInteractions method, which I call from the form’s constructor. The method looks like this:

Initialize

A few considerations:

  • I call the GetInteractionController to get an instance of the Interfaction Controller that’s to be associated with the interaction state machine;
  • I handle the TransitionCompleted event on the state machine (the event handler, shown below, just listens to transition completion on the state machine, and updates the status bar on the customer edit form accordingly);
  • The state machine is then instantiated, with two parameters passed to the constructor:
    • a reference to the interaction controller;
    • an array of IDataInterfaceController objects (which at this point only has a reference to the form itself, since it does implement that interface).

This is the handler for the state machine’s TransitionCompleted event:

TransitionCompleted

At this point, the form is operable. Now I need a few other interface controllers.

Triggering the actions with some fancier buttons

Let’s say that instead of having Load, New, Save buttons placed directly on the form, we wanted to create a fancy user control containing those buttons. Or maybe the buttons were sitting up at a toolbar or ribbon control. It doesn’t matter. The point is that now the form wouldn’t own the buttons anymore. I’ve went with the special user control for this example:

FancyButtons

The user control itself (I’ve named it SimpleDataButtons) is a very simple one: it just has the few buttons sitting on it, and some properties were set just to make it look "fancy" (yeah, right…). The class implements IDataInterfaceController, and the implementation is pretty simple:

SimpleDataButtons

The SetInteractionsStateMachine takes in a reference to the state machine that this controller sends events to, and the properties (NewEnabled, LoadEnabled…) simply interact with the Enabled property on the controls.

The event handlers for the buttons look pretty much the same as we had on the customer edit form; it just sends events to the state machine:

SimpleButtonsHandlers

Now all that’s left to do is to drop the SimpleDataButtons user control on the customer edit form (I’ve named the field simpleDataButtons), and add it to the array of IDataInterfaceControllers:

RegistringSimpleButtons

That’s it. Now when I run the form, I get both set of buttons, and they both work interchangeably (of course, in a real app, I’d have either one or the other…).

Adding shortcuts to trigger the events

Another interface controller that I wanted to add is one that handles keyboard shortcuts. Essentially, I want to access the New, Load, and Save functionality by using Ctrl+N, Ctrl+L, and Ctrl+S, respectively. With the current architecture, this is pretty easy. The "trickiest" part is probably figuring out how to actually handle the keyboard shortcuts. In fact, not too long ago I’ve posted a little design and implementation to do just that (make sure to check out that post!).

For the scope of this post, all you have to know is that I’ve created a DataInterfaceKeyboardHandler (which handles trapping the keystrokes and executing some action depending on the shortcut mapping), and this class implements the IDataInterfaceController interface. Besides receiving a reference to the state machine that the controller sends events to, the implementation of the NewEnabled, LoadEnabled, and SaveEnabled properties essentially does the following:

  • The getter returns true or false, depending on whether or not the specific shortcut is registered with in the list of shortcuts;
  • The setter, registers or un-registers the specific shortcut, depending on whether a true or false is passed to it.

KeyboardHandlers

Again, all the shortcuts do is to send the appropriate events to the state machine. Once again, make sure to check out this post to understand how this DataInterfaceKeyboardHandler class handlers registering, un-registering, and executing keyboard shortcuts.

At this point, it’s only a matter of adding an instance of the keyboard handler to the customer edit form, and add it to the array of IDataInterfaceControllers:

KeyboardHandlerController[5]

If I run the application now, I can either use the buttons or the shortcuts to access the functionality.

Some improvements

One quick improvement to this design and implementation would certainly be a more generic way to register interface controllers with the data entry forms, but I’ll leave that as an exercise to the reader.

Another improvement would be to add functionality to the State Machine Toolkit’s code generator so that, besides generating the state machine, it could also generate the interfaces for the both the interaction and data interface controllers, as well as a default implementation for the state machine (delegating actions to the interaction controller).

I’m going to also, definitely, clean up names so to make the intention of things clearer, and clean up the design as much as possible.

I also want to play with Windows Workflow Foundation (WF), since it has the option to create state machines. Ideally, it’d be good if I could swap what state machine engines I’m using, without having to change anything else in the application.

Summing up

Bringing this thing to the point where I have it right now has been really fun. It allowed me to play with and exercise a lot of cool things, such as state machines, delegates, anonymous types, commands, shortcuts, interfaces, controllers, etc.

I’ll keep working on this thing as I move some of this knowledge into some existing applications, and will certainly post anything else I may that could be interesting for somebody else (or may just as reminder to myself…).

Downloading the source code

Since Microsoft has recently released the MSDN Code Gallery, I’m posting the source code for these posts over there. You can get to it here: GUIInteractions.

6 Comments

VPC on dual monitors

The other day I posted about how I’m now using a VPC machine as my main working machine.

One thing I wasn’t totally thrilled about it, though, is because we can’t benefit from dual monitors when working with the VPC machine. Today I ran across this post, which explains a simple workaround for the issue. There’s also another good post here with a little more details on this. The thing that got me is that I haven’t thought of before is that we can open a remote connection to a VPC machine. How come I didn’t think of that before?!  🙂

Anyway, this is really cool.

Also, I’ve considered using MaxiVista so to make my laptop’s screen as my third monitor, but as it turns out it doesn’t work with the video driver that I have on my machine. Too bad…

Leave a comment

Speaking on TDD at North Houston .NET User Group this week

This Thursday, February 21st, I’ll be speaking at the North Houston .NET user group.

I’ll be talking about Test-Driven Development (TDD). And I heard they got good prizes there, so you may wanna come check it out.  😉

Leave a comment

Windows XP, Vista, and VPC

I’ve migrated to Vista about 6 months ago. At some point, Visual Studio started to run really slow. Quite often, I’d just click somewhere, say in a line on the code editor, and VS would just freeze for minute or two, for no apparent reasons.

VS-not respondingAt some point I thought it could be because I have a bunch of plug-ins installed (CodeRush, RefactorPro, GhostDoc, TestDriven.NET, etc.), even though I didn’t have such problem on Windows XP. I tried removing all plug-ins and giving it a shot; no luck there. It was still behaving the same way.

Next I thought maybe it was a memory issue, since VS is always taking up 500Mb or so. My machine had 2Gb, so we threw in another 2Gb. I also always have a 2Gb ReadyBoost USB drive plugged in. But nope, that didn’t help; VS kept freezing up on me.

I’ve heard of people using a Vista box just as a VPC launcher (that is, the Vista box wouldn’t have much things running on it, and it’d only serve as the means to launch Virtual PC images). I’ve decided to give that a shot. I had actually worked with VPC machines to work as build machines, and also for presentations using beta versions of VS, but haven’t really used them to do actual work. Oh, I have also used it for some debugging.

I went ahead and created a VPC with Windows XP as the operating system, and with just enough things installed on it so that I can do development work, such as Visual Studio, my VS plugins, and client tools for SQL Server (such as Management Studio, but not the actual database server). I have not installed anything else, such as MS Office or things like that. I assign 2Gb of memory to this VPC machine.

As it turns out, working on a 2Gb WinXP + VS VPC machine is a much more pleasant experience than working on a 4Gb Windows Vista + VS + Office + etc machine.

There are other good benefits of working with VPC machines like that:

  • Changes can be easily rolled back by closing the machine without saving its state. This is very helpful, for instance, when you install a plug-in, or any other software for that matter, that messes up with the environment. If that happens, it’s pretty quick to just roll back. Also, if you’ve made a bunch of changes to files and things that get you to a pretty messed up state, just roll it all back. For instance, sometimes I open the VPC machine and I have some files checked out in VS from my previous session. Then I make a bunch of changes and I’m not too happy about it, I can just roll back the machine’s state and start all over.
  • I can easily work on any machine. Since I’ve put the VPC machines on a small USB drive, I can just plug it in to any computer that has Virtual PC installed, and get down to business real quick. This means that if my main computer happens to go through a big crash, I can be back up and running in no time.

This seems to be a pretty good way of to do this, and I’ll keep pursuing it. I have on my to-do list an item for researching some more into how to work with VPC machines effectively (I’m know there’s a LOT of things I need to learn about that, but I do what I can with the time that’s available…).  🙂

2 Comments

Catastrophic Failure??

hmm… VS 2008, Macro Explorer. I right click on a module and try to "new macro", and this is what I get:

msgbox

One would think that kind of message would be gone in VS 2008.  😦

Leave a comment

Migrating a project to VS 2008

I just finished migrating a project from VS 2005 to VS 2008. I’m glad to say that the process went pretty well. No road bumps at all.

I followed the steps below in order to perform the migration:

  1. All developers have checked in their code.
  2. I’ve wiped out my workspace.
  3. Got latest on everything.
  4. Ran all unit and integration tests in the solution.
  5. Wrote down the results of the tests.
  6. Ran some quick smoke tests.
  7. Ran a "check-in build", which is a more restrict build (it runs code analysis, among other things).
  8. Wrote down the results of the check-in build.
  9. Labeled files on TFS ("Last VS 2005 build"), just in case I have to roll it back at some point.
  10. Open the solution in VS 2008 and went through the conversion wizard. Absolutely no errors or warnings were reported.
  11. Built the source code. Didn’t get any error or warning.
  12. Ran all the tests and compared the results to the run in VS 2005. Everything went well.
  13. Ran some quick smoke tests. Everything went well.
  14. Ran a check-in build. No surprises here, but more on this later.
  15. Checked in everything, and oriented the other developers to:
    1. Wipe out the source code in their local folder;
    2. Open the solution using by double-clicking the solution file in Source Control Explorer;
    3. Build it and run it.

The core of this process really didn’t take more than 50 minutes.

Now a word regarding code analysis:

In VS 2005, the Error List window had a limitation where it could only display up to 200 hundred rows. If Code Analysis reported more than that, the build would fail, and an error message would say that there’s more warnings than what the Error List is capable of displaying. In VS 2008, that limitation is gone, so at the end of building the converted source code, I’ve ended up with 13000 code analysis warnings!

This project has a bunch of warnings like that because a big chunk of the code comes from a migration from Visual FoxPro code, and that code violates all sorts of naming convention rules. There’s no way we’re going to fix those names, so we’ve been just supressing those messages. We had done that before, but apparently the new build in VS 2008 didn’t find those suppressions, so now I’m going through the list supressing those violations again.

So, overall I’m pretty happy about how smooth the conversion process went.

Leave a comment

State Machines and GUI interaction – Part I

I’ve been doing some research recently regarding State Machines and GUI (Graphical User Interface) interaction. The motivation for this is that GUI interaction is something that keeps coming back at me one way or another, and it’s always something deemed painful by the developers working in the team.

For instance, let’s take the "enable/disabled" kind of logic: depending on different things, controls on the screen may be enabled or disabled (it could be related to a business rule, or to a security rule, or both). I’ve worked on a project years ago that any developer would shiver just because of the bare thought of having to fix a bug or touch code in a form that had a very heavy enable/disable kind of logic. It was probably one of the most fragile pieces of the application.

With UI’s getting more and more complex, I’ve been doing some research on how I could address this scenario in a way that’s flexible and reliable. I’m not sure I have found the silver bullet yet, but I think I’m getting there.

With this post I’ll start a series of posts where I’ll document my findings, and hopefully get feedback from various people.

A quick simple example

The following excellent book has some good chapters on state machine, state diagrams, and state design pattern:

Agile Principles, Patterns, and Practices in C# (Robert C. Martin Series)
by Robert C. Martin, Micah Martin

Read more about this title…

The book has a very quick but good example for a state machine in the GUI interaction realm. I decided to sit down and write some code that implements the example mentioned in the book. I’m going to quote the book’s explanation of the scenario:

"Imagine that you want to allow your users to draw rectangles on the screen. The gestures they use are as follows. A user clicks the rectangle icon in the pallet window, positions the mouse in the canvas window at one corner of the rectangle, presses the mouse button, and drags the mouse toward the desired second corner. As the user drags, an animated image of the potential rectangle appears on the screen. The user manipulates the rectangle to the desired shape by continuing to hold the mouse button down while dragging the mouse. When the rectangle is right, the user releases the mouse button. The program then stops the animation and draws a fixed rectangle on the screen.

Of course, the user can abort this at any time by clicking a different pallet icon. If the user drags the mouse out of the canvas window, the animation disappears. If the mouse returns to the canvas window, the animation reappears.

Finally, having finished drawing a rectangle, the user can draw another one simply by clicking and dragging again in the canvas window. There is no need to click the rectangle icon in the pallet."

After that explanation, there’s a state diagram, which I’ve roughly reproduced in Visio just to help me out here:

RectangleStateDiagram

A State Machine toolkit and code generator

Somewhere in the book, it explains state machines, the state pattern, and a state machine code generator that the author wrote which is available for download.

The book explains state machines, and it also points out to a code generator that the author wrote that produces code to implement concrete state machines. The core of the explanation can be found in this article. I definitely recommend getting the book, though, since it also offers the code in C#, as well as unit tests that help understanding the design. The SMC (Finite State Machine Compiler) can be downloaded here.

Instead of using the generator mentioned by the book, though, I’ve decided to use the .NET State Machine Toolkit I found on the Code Project website. There are three excellent articles supporting the toolkit, and the articles not only explain state machines, but they also explain the design of the toolkit, how to use it to implement one simple and one slightly more advanced state machine, and how its state machine code generator works and has been implemented. I definitely recommend the reader to check out the tree parts of that article:

A .NET State Machine Toolkit – Part I
A .NET State Machine Toolkit – Part II
A .NET State Machine Toolkit – Part III

The final product of the sample application

The final product of the sample application I built here looks just like a simple form that works as a canvas where the user can draw a rectangle on it. The application changes the mouse pointer as the user draws the rectangle, and also changes it when the user has the left-button pressed but is moving it outside the boundaries of the form. I’ve also implemented a "fancier" version of the drawing algorithm so that it draws multiple rectangles and allows the user to create some simple effects. The fancier version also displays the coordinates of the new rectangle as the user draws it.

FancyFinalProduct

FinalProduct[4]

 

 

 

 

 

 

 

 

Yeah, I know, the application does not look all that exciting, but keep in mind that that’s not the point of this exercise. The idea is that if I have the correct design in place, a developer with good GDI+ plus skills could produce a little component that would take care of rendering some real fancy rectangles. Also, we should be able to take the state machine and implement it, say, in a WPF application.

The Implementation

The quick and dirty implementation of such application would basically override a few methods on the form to capture mouse clicks, do the rendering, etc. If I went that route, what would the code look like when I wanted to provide different implementations of the rendering logic? The code would certainly get very complicated and hard to maintain. Also, what if I wanted to create a WPF version of the application? I’d probably have to rewrite everything from scratch, since the rendering can be accomplished in better ways in WPF than in WinForms.

With all of that in mind I started the implementation of my little application by using the State Machine Maker (from the State Machine Toolkit), to produce a state machine based on the state diagram (showed earlier on in this post):

StateMachineMaker

Here’s a State Transition Table with all the details for our state machine (this is just a simplification of the state diagram presented earlier):

Current State Event New State Action (transition)
WaitingForClick MouseDown Dragging RecordFirstPoint
BeginAnimation
  Abort   StopAnimation
Dragging MouseMove Dragging AnimateRectangle
  MouseLeave OutOfCanvas PauseAnimation
  MouseUp WaitingForClick StopAnimation
DrawRectangle
  Abort   StopAnimation
OutOfCanvas MouseEnter Dragging ResumeAnimation
  Abort   StopAnimation

The next step was to subclass the generated state machine (that way, if I need to regenerate the machine I don’t lose my changes). I named the subclass WinFormsRectangleToolStateMachine (from here on I’ll refer to this class as "the state machine". 

With the state machine ready, I could go ahead and start putting some code inside the "action" methods (such as DrawRectangle, AnimateRectangle, etc.). For instance, the AnimateRectangle method could look like this:

protected override void AnimateRectangle(object[] args)
{
    this.m_SecondPoint = (Point)args[0];
    Graphics g = (Graphics)args[1];
    g.Clear(Color.White);
    this.DrawRectangleCore(g);
}

Just for the records, args contains both the "second point" selected by the user (bottom-right of the rectangle), as well as the Graphics object to draw the rectangle on.

However, what if I wanted to support different algorithms for this "rectangle tool" of mine? Maybe I’d like to have a ways to draw "simple" rectangles, and/or "fancy" rectangles. In order to support these variances, I’d have to stick all the code in my action methods, and branch them into switch blocks or something along those lines.

That said, if I wanted to support a dozen different ways to render rectangles, my class would look pretty nasty and hard to maintain. Not only that, but what if I also needed to allow other people to write the rendering mechanism? I don’t like the idea of having to give them my source code so that they could add a little bit more mess to it.

Put some Controllers into the mix…

I decided to let my "RectangleToolStateMachine" only handle the change of states, but not put any implementation for the actions right into it. Instead, the machine should call out to a "RectangleToolController", which is the object responsible for actually implementing the actions. With that in mind, I’ve defined the following interface:

public interface IRectangleToolController
{
    void RecordFirstPoint(object[] args);
    void BeginAnimation(object[] args);
    void StopAnimation(object[] args);
    void PauseAnimation(object[] args);
    void ResumeAnimation(object[] args);
    void DrawRectangle(object[] args);
    void AnimateRectangle(object[] args);
}

Note that the IRectangleToolController interface declares methods that map to the actions/transitions specified by our state machine.

Next, I’ve changed the constructor for my WinFormsRectangleToolStateMachine so that it takes an instance of an IRectangleToolController:

ctor

And then I changed the implementation of my action methods on the state machine so that they delegate the actual actions to the controller (as opposed to implementing the actions itself):

controller

I’ve then created a WinFormsOption1RectangleToolController class, which implements the IRectangleToolController interface, and filled in the methods with the code that handlers the rendering of simple rectangles.

Now when it comes to using my state machine and controller, it’s all a matter of instantiating the machine and pass a controller into it:

machinecontroller

Triggering the transitions

The only part that’s left is to trigger the transitions on the state machine. Since my machine is used by a simple form (which I called "Canvas"), all I’ve had to do was to hook up to mouse events and trigger the appropriate transitions.

Every transition on my machine expects the same parameters: the Graphics object where we draw on, and the location where the mouse has been either clicked or released. I created a simple method that gathers those two parameters, send them to the state machine, and tell the machine to execute the transition:

private void SendEventToMachine(int eventId, Point mouseLocation)
{
    Graphics g = this.CreateGraphics();
    object[] args = new object[] { mouseLocation, g };

    m_RectangleToolSM.Send(eventId, args);
    m_RectangleToolSM.Execute();
}

And finally, my handlers for the mouse events on the form look pretty much like this:

formevents

In order words, the handlers just send the appropriate events to the state machine. There’s no code in the form whatsoever that deals with rendering rectangle; that responsibility is delegate to the controller associated with the machine (whose only responsibility is to handle the transitions).

Implementing other controllers

Just to try out my design, I created a "FancyWinFormsOption1RectangleToolController" class, which renders much fancier rectangles, and it also displays coordinates on the canvas as to where the rectangle is being rendered (wow! well, ok, I was just trying out the design here, so it’s not like I’ve put a lot of effort into coming up with better ways to render rectangles…).

The fact is that all I had to do was to:

  • Create the new controller class, making it inherit from my IRectangleToolController interface;
  • Implement how the controller handles rendering rectangles and the other methods exposed by the interface;
  • Let my Canvas form know about my new controller.

Nothing else had to be changed. I could certainly have made it even better, by going with a plug-in architecture, where new controllers could be made available to the application just by registering them somehow (but that was beyond the scope of this exercise).

Coming up next…

I’ll write up another post to follow this one. On that new post I’ll describe a design and implementation that I’m considering to address a common UI interaction need. With that post I’ll make available all the source code so that you can it out and hopefully give me some feedback (I’m not posting the code just now because I have some clean up to do).  🙂

2 Comments