Page 4 of 6
At this point we have the necessary code to allow the user to plot a default view of the Mandelbrot set. Next we want to let the user select an area by dragging with a mouse and then recomputing the Mandelbrot set so that this selected area is blown up to cover the entire picture box.
To allow the user to mark out an area we need to make use of the mouse events – mousedown, mousemove and mouseup.
Essentially what we need to do is record the x,y co-ordinates when the user presses the mouse button down. This marks the first corner of the rectangle. Then as the user moves the mouse we animate a rectangle drawn from the first corner to the current mouse position. Finally the user lets go of the mouse button , i.e. a mouseup event occurs, and we store the final mouse co-ordinates of the rectangle.
This sounds easy but as we draw a rectangle by specifying its height, width and top lefthand corner things are a little more tricky. In particular the mouse down position is only the top lefthand corner of the rectangle if the user drags down and to the right. If they drag up and to the left it is the bottom right hand corner. The solution to this problem is to sort the mouse positions to find the top lefthand corner no matter what the two points specified are.
First we might as well create the selection rectangle ready to be used:
private Rectangle selection = new Rectangle()
Stroke= new SolidColorBrush(Colors.Black),
StrokeThickness = 1,
Visibility = Visibility.Collapsed
You can define this Rectangle using XAML is you want but using object initiliasation syntax code is just as easy. We also have to add the Rectangle to the Canvas and the best place to do this is in the contructor:
(Notice that the default name that Silverlight assigns the Canvas is canvas1 whereas WPF assigns Canvas1.)
We also need a flag to signal that a selection is in progress and a Point to store the location the mouse button is first pressed down:
private bool mousedown = false;
private Point mousedownpos;
The mouseLeftButtonDown event handler is:
private void canvas1_MouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
mousedown = true;
mousedownpos = e.GetPosition(canvas1);
selection.Width = 0;
selection.Height = 0;
selection.Visibility = Visibility.Visible;
This is an easy method but there are some subtle points. The first is that the Canvas only receives routed events from image1. We also get the mouse position relative to Canvas1. Then we set the top left hand corner of the selection rectangle to the mouse down position and make it visible.
The MouseMove event handler is only complicated because of the need to identify the top left-hand corner of the rectangle between the two points.
First we have to check that the mousedown event occured - we don't do anything if the mouse is just moving over the Canvas:
private void canvas1_MouseMove(
object sender, MouseEventArgs e)
If the mouse is moving after a down button event then we can retrieve its position and work out the difference between its current position and where the mousedown event occurred:
Point mousepos = e.GetPosition(Canvas1);
Point diff = new Point(
mousepos.X - mousedownpos.X,
mousepos.Y - mousedownpos.Y);
Notice that Silverlight doesn't support arithmetic with Points and Vector types as does WPF. The easiest solution is to simply use the Point structure as an all purpose 2D data type.
We might as well start with the assumption the mousedownpos is the TopLeft hand corner - after all most users drag down and to the right:
Point TopLeft = mousedownpos;
Now we test to see if any of the differences were negative and if so we have to swap a co-ordinate:
if (diff.X < 0)
TopLeft.X = mousepos.X;
diff.X = -diff.X;
if (diff.Y < 0)
TopLeft.Y = mousepos.Y;
diff.Y = -diff.Y;
Notice that now TopLeft really does hold the position of the top left of the rectangle. This, together with the differences, can be used to set the position of the selection:
selection.Width = diff.X;
selection.Height = diff.Y;