Introduction

In this article, I will show you how to move, resize and rotate objects of any type on a canvas. For this, I will provide two different solutions - the first one without and then one with WPF Adorners.

About the Code

MoveResize: This version shows you how to move and resize objects without WPF Adorners.

MoveResizeRotate: In addition, this project provides rotation of objects, still without WPF Adorners. Rotation has some minor side effects that need to be considered when moving or resizing objects. You can easily track these side effects when you compare this project with the previous one.

MoveResizeRotateWithAdorners: The third project finally shows you how to move, resize and rotate items with the help of WPF Adorners. It also gives you an example of how Adorners can be used to provide visual feedback to indicate the actual size of an object during a resize operation.

Preparations

You might not be impressed by this diagram, nevertheless it is a good starting point. It is easy to understand and it has all a basic diagram needs to have: a drawing canvas with a shape. But you are right, this diagram isn't really useful - it's just too static.

So let's start with some preparations by wrapping the ellipse into a ContentControl:

Not much better you may say, we still can't move the ellipse, so what is it good for? Well, the ContentControl serves as a container for the object that we want to place on the canvas and it is actually this ContentControl that we are going to move, resize and rotate! And because the content of a ContentControl can be of any type, we will be able to move, resize and rotate objects of any type on our canvas!

Note: Because of its key role, this ContentControl is also referred to as DesignerItem.

We conclude our preparations by assigning a ControlTemplate to the DesignerItem. This introduces a further level of abstraction, so that from now on we will just expand this template and leave the DesignerItem and its content completely untouched.

Now that we have finished our preparations, we are ready to bring some activity on the canvas.

Move

There is a control in WPF about which the MSDN documentation says: " ...represents a control that lets the user drag and resize controls." That seems to be a perfect candidate for our job. It is the Thumb control and here is how we are going to use it:

The MoveThumb is inherited from Thumb and it provides just an implementation of the DragDelta event handler. Within the event handler, first the DataContext is cast to a ContentControl and then its position is updated according to the horizontal and vertical drag change. You may have already guessed that the control retrieved from the DataContext is our DesignerItem, but where does it come from? You can find the answer if you look at the updated DesignerItem's template:

Here you see that the MoveThumb's DataContext property is bound to the templated parent, which is of course our DesignerItem. Note that we have added a Grid as the layout panel for the template, which allows both the ContentPresenter and the MoveThumb to take in the complete DesignerItem's real estate. Now we can compile and run the code.

As a result, we get a blue ellipse on top of a gray MoveThumb. If you play around with it, you will notice that you can actually grab and drag the object, but only where the gray MoveThumb is visible. That's because the ellipse hinders the mouse events to make its way through to the MoveThumb. We can easily change this behaviour by setting the IsHitTest property of the ellipse to false.

<EllipseFill="Blue"IsHitTestVisible="False"/>

The MoveThumb has inherited its style from the base Thumb class, which is not really appealing in our case. For this, we create a new template consisting of a transparent rectangle only. A more general solution would be to create a default style for the MoveThumb class, but for the moment a customized template will do.

That's all we need to move items on a canvas, now I will show you how to resize objects.

Resize

You remember that the MSDN documentation promised that the Thumb control would let the user drag and resize controls? So, we stick with the Thumb control and build a control template, named ResizeDecoratorTeamplate:

Here you see a control template that consists of a grid filled up with a bunch of 8 Thumb controls, which should work as resize handles. By setting the Thumb properties like we did above, we achieved a layout that results in something that looks like a real resize decorator:

Amazing, isn't it. But so far it is only a fake, because there is no event handler that would handle the DragDelta events of the Thumbs. For this, we replace the Thumb objects by ResizeThumbs:

The ResizeThumbs just update the DesignerItem's width, height and/or position, depending on the ResizeThumb's vertical and horizontal alignment. Now let's integrate the resize decorator into the DesignerItem's control template by adding a Control object with the ResizeDecoratorTemplate.

Perfect, now we can move and resize objects. Next comes rotation of objects.

Rotate

To provide rotation of objects, we follow the same solution path as in the chapter before, but this time we create a RotateThumb and arrange four instances of it in a control template named RotateDecoratorTemplate. Together with the resize decorator, it looks like this:

The structure of the code for RotateThumb and the RotateDecoratorTemplate is very similar to what we have seen in the chapter before, so I will not list the code here.

Note: My first approach to drag, resize and rotate items was to use WPF's TranslateTransform, ScaleTransform and RotateTransform. But that turned out to be the wrong way, because Transforms in WPF do not really change an object's properties like width or height, WPF Transforms are just a rendering issue. So I didn't use TranslateTransform and ScaleTransform to drag and resize items, but I had to use RotateTransform because of no alternative.

DesignerItem Style

For convenience, we wrap the DesignerItem's control template into a style, where we also set various properties like MinWidth, MinHeight and RenderTransformOrigin. A trigger allows us to make the resize and rotate decorator visible only when the item is selected, which is indicated by the attached property Selector.IsSelected.

Note: WPF comes with a class named Selector, which is a control that allows you to select items from among its child elements. I do not make use of this control in this article, but I use the attached Selector.IsSelected property to mimic selection.

That's it. Now we can move, resize and rotate objects. One has to realize that a few lines of XAML code together with three classes provide all we need to do that! Best of all, we don't need to touch the objects themselves: all the behaviour is completely wrapped into a ControlTemplate.

Adorner Based Solution

In this chapter, I present a solution that raises the resize and rotate decorators to the AdornerLayer so that they are rendered on top of all other items.

The adorner based solution is best explained by showing you the resulting DesignerItem's control template:

This template is similar to what we had in the previous chapter, except that the resize and rotate decorators are replaced by an instance of a new class named DesignerItemDecorator. This class is derived from Control and has no own default style, instead the class provides an adorner that becomes visible when the boolean ShowAdorner property gets true.

You see that this adorner has a single visual child of type DesignerItemAdornerChrome, which is actually the control that provides the drag handles to resize and rotate items. This chrome control has a default style which arranges ResizeThumbs and RotateThumbs objects in a way that is similar to what we have seen in the previous chapter, so I will not repeat that code here.

Custom Adorners

You can, of course, add your own customized adorners to a DesignerItem. As an example, I have added an adorner that displays width and height while resizing an object. For more details, please see the attached code. If you have questions, feel free to ask.