Avoiding throwaway layout/painting/mouse code
I’m not normally a Hungarian fanatic or anything, but it is quite easy to create “write once” layout/painting code. If there’s ever a problem with the math the code needs to be tossed out because it’s too confusing or too difficult to update.
I think we've all either seen this kind of code and/or have been guilty of writing it at one point... in the interests of reducing frustration for everyone I've got a few tips to write more maintainable UI code.
Label things what they mean
Rect r = new Rect(button1.RenderSize);
Consider something like:
Rect button1Bounds = new Rect(button1.RenderSize);
If it’s something not within the button’s coordinate system, then label it by the coordinate system it is in:
e.g. Rect button1BoundsInWindowCoords;
When creating transforms, consider labelling them in fromTo notation:
e.g. Transform button1ToWindowTransform = button1.TransformToAncestor(window) as Transform;
This helps you when you’re in the debugger – if you have “t” in your watch window you don’t know which transform you meant when you were writing your code. I get out a piece of paper and prove the math, and then I verify that my variables are as expected in the debugger. You can really only use this method if the variables mean something that can’t be changed.
Avoid UI “fudges” if possible. If you must fudge comment it!
Whenever there’s a fudge, you’re quite likely to be revisiting that code in a few days. Try to figure out why you need that extra 1PX and put it in a comment next to the code.
Define reference rectangles and work within them
If you only want to do something when something is in the first five pixels of your control, don’t be afraid to create and maintain your own rectangles. The good thing about reference rectangles is that you can draw them out and see if they are in the right spot.
Rectangle topDropZone = new Rect(0,0,this.Width, 25);
Learn the methods on Rect/Rectangle/Point/Size/Vector
There are a lot of built in methods that help keep your math tidy. It’s worth looking at the APIs in some tool or in MSDN to see what can make your life easier.
Here are a few examples from WPF/Silverlight (most are true of System.Drawing as well):
//Rectangle provides intersection/union methods
Rect selectedArea = rubberBandRect.Intersect(controlBounds);
// Inflate is very handy for increasing the size of a rectangle in all dimensions
Rect borderArea = controlBounds.Inflate(1,1); // x-=1, y-=1, width +=2, height+=2.
// Offset is very handy for adding to X & Y
Point startingLocation = new Point(10,20);
startingLocation.Offset(30,40); // adds 30 to x and 40 to y
// you can cast a vector to a point or size.
Vector someVector = new Vector(100,20);
Point somePoint = (Point)someVector;
Size someSize = (Size)someVector;
Got any tips?