On Jun 2nd and 3rd I’ll be speaking at the PrairieDevCon 2010 in Regina!!! You can read about it at http://www.prairiedevcon.com/. It would be two complete days of sessions with four tracks and many cool speakers!!!! I will do two presentations:
New inspirationOne of many great things about blogging is that you get feedback from other developers. My good friend Sebastian (@paraseba) suggested to use a Chain-of-Responsibility instead of a Composite to find the an active snapping strategy. If u have no idea what I'm talking about, please read the previous post about "Implementing a Snapping Strategy".
CoR PatternIn the Design Patterns book, the authors describe the Chain of Responsibility pattern like this:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.In our case this means that we should give the opportunity to each strategy to do the snapping and if no snapping is available should call the “chained” strategy to see if the point should be snapped. The solution it's working, good time to refactor (Red, Green, Refactor) to add more flexibility to our strategies. Let’s explore what changes do we need to do in order to be able to chain the strategies.
Chained StrategiesI don’t think we should modify the interface, no one needs to know which pattern are we implemented, so I am going to create a new abstract class called ChainedSnappingStrategy. This class will be the base implementation for all the other strategies with two responsibilities:
- Call the next strategy in the chain if no snapping was applied
- If it’s the end of the chain, return the same point.
The applicationFor the past eight months I’ve been working on a WPF desktop application that has a tool to draw. Very similar to most drawing application, you select the Drawing tool in the ribbon/toolbox and then you are able to draw on the canvas until you close the shape or cancel the tool.
The new requirementNow, we need to draw using snapping. Snapping means that when you are drawing close to a particular point (considering a distance) the mouse will move but the drawing line not, will stay snapped to the point. In this case we need to consider three cases:
- Snapping on the X axis (horizontal axis)
- Snapping on the Y axis (vertical axis)
- Snapping when the line has an 90 degree angle with the previous line
Where should I add the snapping?So I started by writing a test (Yes, full TDD) that checks when I’m close to the X axis (3 pixels or less) then the drawing tool should snap. My test failed gloriously and I was ready to start my implementation in order to make the test pass… now… the question is… who is responsible for snapping?
The Drawing ToolLet’s review the drawing tool interaction to understand how it works using MVVM.
- The Canvas receives a mouse move event and passes that information to the DrawingTool
- The DrawingTool raises a LineMoved event
- The view model receives the event and notifies the view
- The view shows the line ending on the new point